import type { DeploymentLoader } from "../internal/deployment-loader/types.js"; import type { JsonRpcClient } from "../internal/execution/jsonrpc-client.js"; import type { CallExecutionState, DeploymentExecutionState, SendDataExecutionState, StaticCallExecutionState, } from "../internal/execution/types/execution-state.js"; import type { CallStrategyGenerator, DeploymentStrategyGenerator, ExecutionStrategy, SendDataStrategyGenerator, StaticCallStrategyGenerator, } from "../internal/execution/types/execution-strategy.js"; import { decodeArtifactCustomError, decodeArtifactFunctionCallResult, encodeArtifactDeploymentData, encodeArtifactFunctionCall, executeOnchainInteractionRequest, executeStaticCallRequest, getStaticCallExecutionStateResultValue, } from "../internal/execution/execution-strategy-helpers.js"; import { ExecutionResultType } from "../internal/execution/types/execution-result.js"; import { OnchainInteractionResponseType } from "../internal/execution/types/execution-strategy.js"; import { NetworkInteractionType } from "../internal/execution/types/network-interaction.js"; import { assertIgnitionInvariant } from "../internal/utils/assertions.js"; /** * The basic execution strategy, which sends a single transaction * for each contract deployment, call, and send data, and a single static call * for each static call execution. * * @private */ export class BasicStrategy implements ExecutionStrategy { public readonly name: string = "basic"; public readonly config: Record; private _deploymentLoader: DeploymentLoader | undefined; constructor() { this.config = {}; } public async init( deploymentLoader: DeploymentLoader, _jsonRpcClient: JsonRpcClient, ): Promise { this._deploymentLoader = deploymentLoader; } public async *executeDeployment( executionState: DeploymentExecutionState, ): DeploymentStrategyGenerator { assertIgnitionInvariant( this._deploymentLoader !== undefined, `Strategy ${this.name} not initialized`, ); const artifact = await this._deploymentLoader.loadArtifact( executionState.artifactId, ); const transactionOrResult = yield* executeOnchainInteractionRequest( executionState.id, { id: 1, type: NetworkInteractionType.ONCHAIN_INTERACTION, to: undefined, data: encodeArtifactDeploymentData( artifact, executionState.constructorArgs, executionState.libraries, ), value: executionState.value, }, undefined, (returnData) => decodeArtifactCustomError(artifact, returnData), ); if ( transactionOrResult.type !== OnchainInteractionResponseType.SUCCESSFUL_TRANSACTION ) { return transactionOrResult; } const tx = transactionOrResult.transaction; const contractAddress = tx.receipt.contractAddress; if (contractAddress === undefined) { return { type: ExecutionResultType.STRATEGY_ERROR, error: `Transaction ${tx.hash} confirmed but it didn't create a contract`, }; } return { type: ExecutionResultType.SUCCESS, address: contractAddress, }; } public async *executeCall( executionState: CallExecutionState, ): CallStrategyGenerator { assertIgnitionInvariant( this._deploymentLoader !== undefined, `Strategy ${this.name} not initialized`, ); const artifact = await this._deploymentLoader.loadArtifact( executionState.artifactId, ); const transactionOrResult = yield* executeOnchainInteractionRequest( executionState.id, { id: 1, type: NetworkInteractionType.ONCHAIN_INTERACTION, to: executionState.contractAddress, data: encodeArtifactFunctionCall( artifact, executionState.functionName, executionState.args, ), value: executionState.value, }, (returnData) => decodeArtifactFunctionCallResult( artifact, executionState.functionName, returnData, ), (returnData) => decodeArtifactCustomError(artifact, returnData), ); if ( transactionOrResult.type !== OnchainInteractionResponseType.SUCCESSFUL_TRANSACTION ) { return transactionOrResult; } return { type: ExecutionResultType.SUCCESS, }; } public async *executeSendData( executionState: SendDataExecutionState, ): SendDataStrategyGenerator { const transactionOrResult = yield* executeOnchainInteractionRequest( executionState.id, { id: 1, type: NetworkInteractionType.ONCHAIN_INTERACTION, to: executionState.to, data: executionState.data, value: executionState.value, }, ); if ( transactionOrResult.type !== OnchainInteractionResponseType.SUCCESSFUL_TRANSACTION ) { return transactionOrResult; } return { type: ExecutionResultType.SUCCESS, }; } public async *executeStaticCall( executionState: StaticCallExecutionState, ): StaticCallStrategyGenerator { assertIgnitionInvariant( this._deploymentLoader !== undefined, `Strategy ${this.name} not initialized`, ); const artifact = await this._deploymentLoader.loadArtifact( executionState.artifactId, ); const decodedResultOrError = yield* executeStaticCallRequest( { id: 1, type: NetworkInteractionType.STATIC_CALL, to: executionState.contractAddress, from: executionState.from, data: encodeArtifactFunctionCall( artifact, executionState.functionName, executionState.args, ), value: 0n, }, (returnData) => decodeArtifactFunctionCallResult( artifact, executionState.functionName, returnData, ), (returnData) => decodeArtifactCustomError(artifact, returnData), ); if (decodedResultOrError.type === ExecutionResultType.STATIC_CALL_ERROR) { return decodedResultOrError; } return { type: ExecutionResultType.SUCCESS, value: getStaticCallExecutionStateResultValue( executionState, decodedResultOrError, ), }; } }