From 17bd929b987a6ca0a6357f20649d08db4ff8f0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Torres?= <30977845+Torres-ssf@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:47:54 -0300 Subject: [PATCH] feat!: made `deployContract` a non-blocking call (#2597) --- .changeset/tender-eyes-think.md | 8 ++ .../src/pages/index.tsx | 4 +- apps/demo-bun-fuels/src/bun.test.ts | 17 ++- apps/demo-fuels/src/index.test.ts | 17 ++- apps/demo-typegen/src/demo.test.ts | 17 ++- .../contracts/configurable-constants.test.ts | 8 +- .../contracts/deploying-contracts.test.ts | 13 ++- .../contracts/inter-contract-calls.test.ts | 8 +- .../managing-deployed-contracts.test.ts | 4 +- .../src/guide/contracts/multicalls.test.ts | 14 ++- ...custom-transactions-contract-calls.test.ts | 4 +- .../cookbook/deposit-and-withdraw.test.ts | 3 +- .../cookbook/transferring-assets.test.ts | 3 +- .../scripts/script-custom-transaction.test.ts | 3 +- apps/docs-snippets/src/utils.ts | 5 +- .../guide/contracts/deploying-contracts.md | 8 +- .../src/templates/contract/factory.hbs | 10 +- .../fixtures/templates/contract/factory.hbs | 10 +- .../transaction-response.ts | 28 ++++- packages/contract/src/contract-factory.ts | 104 ++++++++++++------ packages/contract/src/index.ts | 6 +- .../src/test-utils/launch-test-node.ts | 21 ++-- packages/fuel-gauge/src/auth-testing.test.ts | 3 +- .../src/configurable-contract.test.ts | 58 ++++++++-- .../fuel-gauge/src/contract-factory.test.ts | 36 +++--- packages/fuel-gauge/src/contract.test.ts | 19 +++- .../src/dry-run-multiple-txs.test.ts | 22 ++-- packages/fuel-gauge/src/fee.test.ts | 12 +- .../utils/predicate/setupContract.ts | 3 +- .../src/reentrant-contract-calls.test.ts | 10 +- packages/fuel-gauge/src/revert-error.test.ts | 6 +- .../src/storage-test-contract.test.ts | 6 +- .../src/token-test-contract.test.ts | 4 +- packages/fuel-gauge/src/utils.ts | 11 +- .../src/cli/commands/deploy/deployContract.ts | 4 +- 35 files changed, 345 insertions(+), 164 deletions(-) create mode 100644 .changeset/tender-eyes-think.md diff --git a/.changeset/tender-eyes-think.md b/.changeset/tender-eyes-think.md new file mode 100644 index 00000000000..e056e29fc0c --- /dev/null +++ b/.changeset/tender-eyes-think.md @@ -0,0 +1,8 @@ +--- +"@fuel-ts/abi-typegen": minor +"@fuel-ts/contract": minor +"@fuel-ts/account": minor +"fuels": minor +--- + +feat!: made `deployContract` a non-blocking call diff --git a/apps/create-fuels-counter-guide/src/pages/index.tsx b/apps/create-fuels-counter-guide/src/pages/index.tsx index 0f240b25f1b..26fe8919500 100644 --- a/apps/create-fuels-counter-guide/src/pages/index.tsx +++ b/apps/create-fuels-counter-guide/src/pages/index.tsx @@ -12,7 +12,7 @@ import { Button } from "@/components/Button"; import toast from "react-hot-toast"; import { useActiveWallet } from "@/hooks/useActiveWallet"; import useAsync from "react-use/lib/useAsync"; -import { CURRENT_ENVIRONMENT } from '@/lib' +import { CURRENT_ENVIRONMENT } from '@/lib'; // #region deploying-dapp-to-testnet-frontend-contract-id const contractId = @@ -37,7 +37,7 @@ export default function Home() { */ useAsync(async () => { if (hasContract && wallet) { - const testContract = TestContractAbi__factory.connect(contractId, wallet); + const { contract: testContract } = TestContractAbi__factory.connect(contractId, wallet); setContract(testContract); const { value } = await testContract.functions.get_count().get(); setCounter(value.toNumber()); diff --git a/apps/demo-bun-fuels/src/bun.test.ts b/apps/demo-bun-fuels/src/bun.test.ts index 61be13cd841..ccd805c089a 100644 --- a/apps/demo-bun-fuels/src/bun.test.ts +++ b/apps/demo-bun-fuels/src/bun.test.ts @@ -6,7 +6,7 @@ */ import { ContractFactory, Provider, toHex, Wallet, FUEL_NETWORK_URL } from 'fuels'; -import { generateTestWallet , safeExec } from 'fuels/test-utils'; +import { generateTestWallet, safeExec } from 'fuels/test-utils'; import { SampleAbi__factory } from './sway-programs-api'; import bytecode from './sway-programs-api/contracts/SampleAbi.hex'; @@ -28,7 +28,8 @@ describe('ExampleContract', () => { // Deploy const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); // Call const { value } = await contract.functions.return_input(1337).call(); @@ -47,7 +48,8 @@ describe('ExampleContract', () => { const wallet = await generateTestWallet(provider, [[500_000, baseAssetId]]); // Deploy - const contract = await SampleAbi__factory.deployContract(bytecode, wallet); + const { waitForResult } = await SampleAbi__factory.deployContract(bytecode, wallet); + const { contract } = await waitForResult(); // Call const { value } = await contract.functions.return_input(1337).call(); @@ -62,7 +64,8 @@ describe('ExampleContract', () => { const unfundedWallet = Wallet.generate({ provider }); const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, fundedWallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const contractInstance = SampleAbi__factory.connect(contract.id, unfundedWallet); const { error } = await safeExec(() => @@ -78,7 +81,8 @@ describe('ExampleContract', () => { const unfundedWallet = Wallet.generate({ provider }); const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, fundedWallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const contractInstance = SampleAbi__factory.connect(contract.id, unfundedWallet); await expect(contractInstance.functions.return_input(1337).dryRun()).resolves.not.toThrow(); @@ -87,7 +91,8 @@ describe('ExampleContract', () => { it('should demo how to use generated files just fine', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const wallet = await generateTestWallet(provider, [[500_000, baseAssetId]]); - const depoloyed = await SampleAbi__factory.deployContract(bytecode, wallet); + const { waitForResult } = await SampleAbi__factory.deployContract(bytecode, wallet); + const { contract: depoloyed } = await waitForResult(); const contractsIds = { sample: depoloyed.id, }; diff --git a/apps/demo-fuels/src/index.test.ts b/apps/demo-fuels/src/index.test.ts index 0cfc7ff93c2..0e22ee3413b 100644 --- a/apps/demo-fuels/src/index.test.ts +++ b/apps/demo-fuels/src/index.test.ts @@ -6,7 +6,7 @@ */ import { ContractFactory, Provider, toHex, Wallet, FUEL_NETWORK_URL } from 'fuels'; -import { generateTestWallet , safeExec } from 'fuels/test-utils'; +import { generateTestWallet, safeExec } from 'fuels/test-utils'; import { SampleAbi__factory } from './sway-programs-api'; import bytecode from './sway-programs-api/contracts/SampleAbi.hex'; @@ -28,7 +28,8 @@ describe('ExampleContract', () => { // Deploy const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); // Call const { value } = await contract.functions.return_input(1337).call(); @@ -47,7 +48,8 @@ describe('ExampleContract', () => { const wallet = await generateTestWallet(provider, [[500_000, baseAssetId]]); // Deploy - const contract = await SampleAbi__factory.deployContract(bytecode, wallet); + const { waitForResult } = await SampleAbi__factory.deployContract(bytecode, wallet); + const { contract } = await waitForResult(); // Call const { value } = await contract.functions.return_input(1337).call(); @@ -62,7 +64,8 @@ describe('ExampleContract', () => { const unfundedWallet = Wallet.generate({ provider }); const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, fundedWallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const contractInstance = SampleAbi__factory.connect(contract.id, unfundedWallet); const { error } = await safeExec(() => @@ -78,7 +81,8 @@ describe('ExampleContract', () => { const unfundedWallet = Wallet.generate({ provider }); const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, fundedWallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const contractInstance = SampleAbi__factory.connect(contract.id, unfundedWallet); await expect(contractInstance.functions.return_input(1337).dryRun()).resolves.not.toThrow(); @@ -87,7 +91,8 @@ describe('ExampleContract', () => { it('should demo how to use generated files just fine', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const wallet = await generateTestWallet(provider, [[500_000, baseAssetId]]); - const depoloyed = await SampleAbi__factory.deployContract(bytecode, wallet); + const { waitForResult } = await SampleAbi__factory.deployContract(bytecode, wallet); + const { contract: depoloyed } = await waitForResult(); const contractsIds = { sample: depoloyed.id, }; diff --git a/apps/demo-typegen/src/demo.test.ts b/apps/demo-typegen/src/demo.test.ts index 26f55d2bb7c..bf58d3e7db6 100644 --- a/apps/demo-typegen/src/demo.test.ts +++ b/apps/demo-typegen/src/demo.test.ts @@ -1,6 +1,6 @@ // #region Testing-in-ts-ts import { ContractFactory, Provider, toHex, Wallet, FUEL_NETWORK_URL, Address } from 'fuels'; -import { generateTestWallet , safeExec } from 'fuels/test-utils'; +import { generateTestWallet, safeExec } from 'fuels/test-utils'; import storageSlots from '../contract/out/release/demo-contract-storage_slots.json'; @@ -27,9 +27,10 @@ describe('ExampleContract', () => { // #region typegen-demo-contract-storage-slots // #context import storageSlots from './contract/out/debug/demo-contract-storage_slots.json'; - const contract = await DemoContractAbi__factory.deployContract(bytecode, wallet, { + const { waitForResult } = await DemoContractAbi__factory.deployContract(bytecode, wallet, { storageSlots, }); + const { contract } = await waitForResult(); // #endregion typegen-demo-contract-storage-slots expect(contract.id).toBeTruthy(); @@ -40,7 +41,8 @@ describe('ExampleContract', () => { // Deploy const factory = new ContractFactory(bytecode, DemoContractAbi__factory.abi, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const contractId = contract.id; // Call @@ -68,7 +70,8 @@ describe('ExampleContract', () => { // #context import bytecode from './types/DemoContractAbi.hex'; // Deploy - const contract = await DemoContractAbi__factory.deployContract(bytecode, wallet); + const { waitForResult } = await DemoContractAbi__factory.deployContract(bytecode, wallet); + const { contract } = await waitForResult(); // #endregion typegen-demo-contract-factory-deploy @@ -87,7 +90,8 @@ it('should throw when simulating via contract factory with wallet with no resour const unfundedWallet = Wallet.generate({ provider }); const factory = new ContractFactory(bytecode, DemoContractAbi__factory.abi, fundedWallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const contractInstance = DemoContractAbi__factory.connect(contract.id, unfundedWallet); const { error } = await safeExec(() => contractInstance.functions.return_input(1337).simulate()); @@ -101,7 +105,8 @@ it('should not throw when dry running via contract factory with wallet with no r const unfundedWallet = Wallet.generate({ provider }); const factory = new ContractFactory(bytecode, DemoContractAbi__factory.abi, fundedWallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const contractInstance = DemoContractAbi__factory.connect(contract.id, unfundedWallet); await expect(contractInstance.functions.return_input(1337).dryRun()).resolves.not.toThrow(); diff --git a/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts b/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts index 5fe6b9d181a..8892a1d0c87 100644 --- a/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts +++ b/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts @@ -47,9 +47,11 @@ describe('configurable-constants', () => { const factory = new ContractFactory(bin, abi, wallet); - const contract = await factory.deployContract({ + const { waitForResult } = await factory.deployContract({ configurableConstants, }); + + const { contract } = await waitForResult(); // #endregion configurable-constants-2 const { value } = await contract.functions.echo_configurables(true).simulate(); @@ -68,9 +70,11 @@ describe('configurable-constants', () => { const factory = new ContractFactory(bin, abi, wallet); - const contract = await factory.deployContract({ + const { waitForResult } = await factory.deployContract({ configurableConstants, }); + + const { contract } = await waitForResult(); // #endregion configurable-constants-3 const { value } = await contract.functions.echo_configurables(false).simulate(); diff --git a/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts b/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts index 9517d093aa5..5efc4f500c1 100644 --- a/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts +++ b/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts @@ -44,13 +44,20 @@ describe(__filename, () => { // #region contract-setup-3 const factory = new ContractFactory(byteCode, abi, wallet); - const contract = await factory.deployContract(); + const { contractId, transactionId, waitForResult } = await factory.deployContract(); // #endregion contract-setup-3 // #region contract-setup-4 - const { value } = await contract.functions.echo_u8(15).simulate(); + const { contract, transactionResult } = await waitForResult(); + // #endregion contract-setup-4 + + // #region contract-setup-5 + const { value } = await contract.functions.echo_u8(15).call(); + // #endregion contract-setup-5 + expect(transactionId).toBeDefined(); + expect(contractId).toBeDefined(); + expect(transactionResult.isStatusSuccess).toBeTruthy(); expect(value).toBe(15); - // #endregion contract-setup-4 }); }); diff --git a/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts b/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts index 1cb30bf77f4..73a71094f0f 100644 --- a/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts +++ b/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts @@ -21,17 +21,21 @@ describe(__filename, () => { const tokenArtifacts = getDocsSnippetsForcProject(DocSnippetProjectsEnum.SIMPLE_TOKEN); const depositorArtifacts = getDocsSnippetsForcProject(DocSnippetProjectsEnum.TOKEN_DEPOSITOR); - simpleToken = await new ContractFactory( + const { waitForResult } = await new ContractFactory( tokenArtifacts.binHexlified, tokenArtifacts.abiContents, wallet ).deployContract(); - tokenDepositor = await new ContractFactory( + ({ contract: simpleToken } = await waitForResult()); + + const { waitForResult: waitForResult2 } = await new ContractFactory( depositorArtifacts.binHexlified, depositorArtifacts.abiContents, wallet ).deployContract(); + + ({ contract: tokenDepositor } = await waitForResult2()); }); it('should successfully make call to another contract', async () => { diff --git a/apps/docs-snippets/src/guide/contracts/managing-deployed-contracts.test.ts b/apps/docs-snippets/src/guide/contracts/managing-deployed-contracts.test.ts index d57d059d365..4e0658f7d11 100644 --- a/apps/docs-snippets/src/guide/contracts/managing-deployed-contracts.test.ts +++ b/apps/docs-snippets/src/guide/contracts/managing-deployed-contracts.test.ts @@ -21,8 +21,8 @@ describe(__filename, () => { beforeAll(async () => { wallet = await getTestWallet(); const factory = new ContractFactory(bin, abi, wallet); - contract = await factory.deployContract(); - + const { waitForResult } = await factory.deployContract(); + ({ contract } = await waitForResult()); contractId = contract.id; }); diff --git a/apps/docs-snippets/src/guide/contracts/multicalls.test.ts b/apps/docs-snippets/src/guide/contracts/multicalls.test.ts index 7de5d3686c2..638a4efa53f 100644 --- a/apps/docs-snippets/src/guide/contracts/multicalls.test.ts +++ b/apps/docs-snippets/src/guide/contracts/multicalls.test.ts @@ -42,11 +42,17 @@ describe(__filename, () => { wallet ); - echoContract = await factory1.deployContract(); - counterContract = await factory2.deployContract({ + let { waitForResult } = await factory1.deployContract(); + ({ contract: echoContract } = await waitForResult()); + + ({ waitForResult } = await factory2.deployContract({ storageSlots: counterArtifacts.storageSlots, - }); - contextContract = await factory3.deployContract(); + })); + + ({ contract: counterContract } = await waitForResult()); + + ({ waitForResult } = await factory3.deployContract()); + ({ contract: contextContract } = await waitForResult()); }); it('should successfully submit multiple calls from the same contract function', async () => { diff --git a/apps/docs-snippets/src/guide/cookbook/custom-transactions-contract-calls.test.ts b/apps/docs-snippets/src/guide/cookbook/custom-transactions-contract-calls.test.ts index f1809ef3d26..c54befc0472 100644 --- a/apps/docs-snippets/src/guide/cookbook/custom-transactions-contract-calls.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/custom-transactions-contract-calls.test.ts @@ -24,10 +24,10 @@ describe('Custom Transactions from Contract Calls', () => { senderWallet = await getTestWallet(); receiverWallet = Wallet.generate({ provider: senderWallet.provider }); const factory = new ContractFactory(binHexlified, abiContents, senderWallet); - contract = await factory.deployContract({ storageSlots }); + const { waitForResult } = await factory.deployContract({ storageSlots }); + ({ contract } = await waitForResult()); abi = abiContents; baseAssetId = senderWallet.provider.getBaseAssetId(); - contract = await factory.deployContract({ storageSlots }); }); it('creates a custom transaction from a contract call', async () => { diff --git a/apps/docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts b/apps/docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts index 43a8a4f956a..babecf3ceaa 100644 --- a/apps/docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts @@ -25,9 +25,10 @@ describe(__filename, () => { provider = sender.provider; baseAssetId = provider.getBaseAssetId(); const factory = new ContractFactory(binHexlified, abiContents, sender); - liquidityPoolContract = await factory.deployContract({ + const { waitForResult } = await factory.deployContract({ configurableConstants: { TOKEN: { bits: baseAssetId } }, }); + ({ contract: liquidityPoolContract } = await waitForResult()); }); it('deposit and withdraw cookbook guide', async () => { diff --git a/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts b/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts index 9c0336dbba9..69777c726db 100644 --- a/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts @@ -23,7 +23,8 @@ describe(__filename, () => { ); provider = sender.provider; const factory = new ContractFactory(binHexlified, abiContents, sender); - deployedContract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + ({ contract: deployedContract } = await waitForResult()); }); it('should successfully transfer asset to another account', async () => { diff --git a/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts b/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts index 5240fa86132..942b9ba7e13 100644 --- a/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts +++ b/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts @@ -42,7 +42,8 @@ describe(__filename, () => { ]; wallet = await getTestWallet(seedQuantities); const factory = new ContractFactory(contractBin, contractAbi, wallet); - contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + ({ contract } = await waitForResult()); }); it('transfer multiple assets to a contract', async () => { diff --git a/apps/docs-snippets/src/utils.ts b/apps/docs-snippets/src/utils.ts index 0ec3dec55c9..3e7a35a009d 100644 --- a/apps/docs-snippets/src/utils.ts +++ b/apps/docs-snippets/src/utils.ts @@ -56,9 +56,12 @@ export const createAndDeployContractFromProject = async ( const contractFactory = new ContractFactory(binHexlified, abiContents, wallet); - return contractFactory.deployContract({ + const { waitForResult } = await contractFactory.deployContract({ storageSlots, }); + + const { contract } = await waitForResult(); + return contract; }; export const defaultTxParams = { diff --git a/apps/docs/src/guide/contracts/deploying-contracts.md b/apps/docs/src/guide/contracts/deploying-contracts.md index 76fcbe6c75d..1defa7265da 100644 --- a/apps/docs/src/guide/contracts/deploying-contracts.md +++ b/apps/docs/src/guide/contracts/deploying-contracts.md @@ -27,14 +27,18 @@ Load the contract bytecode and JSON ABI, generated from the Sway source, into th ## 4. Deploying the Contract -Initialize a [`ContractFactory`](../../api/Contract/ContractFactory.md) with the bytecode, ABI, and wallet. Deploy the contract and use its methods. +To deploy the contract, instantiate the [`ContractFactory`](../../api/Contract/ContractFactory.md) with the bytecode, ABI, and wallet. Then, call the `deployContract` method. This call resolves as soon as the transaction to deploy the contract is submitted and returns three items: the `contractId`, the `transactionId` and a `waitForResult` function. <<< @/../../docs-snippets/src/guide/contracts/deploying-contracts.test.ts#contract-setup-3{ts:line-numbers} +The `contract` instance will be returned only after calling `waitForResult` and waiting for it to resolve. To avoid blocking the rest of your code, you can attach this promise to a hook or listener that will use the contract only after it is fully deployed. + +<<< @/../../docs-snippets/src/guide/contracts/deploying-contracts.test.ts#contract-setup-4{ts:line-numbers} + ## 5. Executing a Contract Call Now that the contract is deployed, you can interact with it. In the following steps, you'll learn how to execute contract calls. -<<< @/../../docs-snippets/src/guide/contracts/deploying-contracts.test.ts#contract-setup-4{ts:line-numbers} +<<< @/../../docs-snippets/src/guide/contracts/deploying-contracts.test.ts#contract-setup-5{ts:line-numbers} For a more comprehensive TypeScript-backed Fuel usage, learn how to [generate types from ABI](../fuels-cli/generating-types.md) diff --git a/packages/abi-typegen/src/templates/contract/factory.hbs b/packages/abi-typegen/src/templates/contract/factory.hbs index eaf2adcbde2..94a1deaa430 100644 --- a/packages/abi-typegen/src/templates/contract/factory.hbs +++ b/packages/abi-typegen/src/templates/contract/factory.hbs @@ -1,7 +1,7 @@ {{header}} import { Interface, Contract, ContractFactory } from "fuels"; -import type { Provider, Account, AbstractAddress, BytesLike, DeployContractOptions, StorageSlot } from "fuels"; +import type { Provider, Account, AbstractAddress, BytesLike, DeployContractOptions, StorageSlot, DeployContractResult } from "fuels"; import type { {{capitalizedName}}, {{capitalizedName}}Interface } from "../{{capitalizedName}}"; const _abi = {{abiJsonString}}; @@ -28,14 +28,12 @@ export const {{capitalizedName}}__factory = { bytecode: BytesLike, wallet: Account, options: DeployContractOptions = {} - ): Promise<{{capitalizedName}}> { + ): Promise> { const factory = new ContractFactory(bytecode, _abi, wallet); - const contract = await factory.deployContract({ + return factory.deployContract<{{capitalizedName}}>({ storageSlots: _storageSlots, ...options, }); - - return contract as unknown as {{capitalizedName}}; - } + }, } diff --git a/packages/abi-typegen/test/fixtures/templates/contract/factory.hbs b/packages/abi-typegen/test/fixtures/templates/contract/factory.hbs index ed48315619c..579b80ce355 100644 --- a/packages/abi-typegen/test/fixtures/templates/contract/factory.hbs +++ b/packages/abi-typegen/test/fixtures/templates/contract/factory.hbs @@ -10,7 +10,7 @@ */ import { Interface, Contract, ContractFactory } from "fuels"; -import type { Provider, Account, AbstractAddress, BytesLike, DeployContractOptions, StorageSlot } from "fuels"; +import type { Provider, Account, AbstractAddress, BytesLike, DeployContractOptions, StorageSlot, DeployContractResult } from "fuels"; import type { MyContractAbi, MyContractAbiInterface } from "../MyContractAbi"; const _abi = { @@ -79,14 +79,12 @@ export const MyContractAbi__factory = { bytecode: BytesLike, wallet: Account, options: DeployContractOptions = {} - ): Promise { + ): Promise> { const factory = new ContractFactory(bytecode, _abi, wallet); - const contract = await factory.deployContract({ + return factory.deployContract({ storageSlots: _storageSlots, ...options, }); - - return contract as unknown as MyContractAbi; - } + }, } diff --git a/packages/account/src/providers/transaction-response/transaction-response.ts b/packages/account/src/providers/transaction-response/transaction-response.ts index d9bb3f05004..201e5b53dec 100644 --- a/packages/account/src/providers/transaction-response/transaction-response.ts +++ b/packages/account/src/providers/transaction-response/transaction-response.ts @@ -242,15 +242,20 @@ export class TransactionResponse { } /** - * Waits for transaction to complete and returns the result. + * Assembles the result of a transaction by retrieving the transaction summary, + * decoding logs (if available), and handling transaction failure. * - * @returns The completed transaction result + * This method can be used to obtain the result of a transaction that has just + * been submitted or one that has already been processed. + * + * @template TTransactionType - The type of the transaction. + * @param contractsAbiMap - The map of contract ABIs. + * @returns - The assembled transaction result. + * @throws If the transaction status is a failure. */ - async waitForResult( + async assembleResult( contractsAbiMap?: AbiMap ): Promise> { - await this.waitForStatusChange(); - const transactionSummary = await this.getTransactionSummary(contractsAbiMap); const transactionResult: TransactionResult = { @@ -274,7 +279,6 @@ export class TransactionResponse { if (gqlTransaction.status?.type === 'FailureStatus') { const { reason } = gqlTransaction.status; - throw extractTxError({ receipts, statusReason: reason, @@ -285,6 +289,18 @@ export class TransactionResponse { return transactionResult; } + /** + * Waits for transaction to complete and returns the result. + * + * @returns The completed transaction result + */ + async waitForResult( + contractsAbiMap?: AbiMap + ): Promise> { + await this.waitForStatusChange(); + return this.assembleResult(contractsAbiMap); + } + /** * Waits for transaction to complete and returns the result. * diff --git a/packages/contract/src/contract-factory.ts b/packages/contract/src/contract-factory.ts index 76edd8b3696..362d0abf025 100644 --- a/packages/contract/src/contract-factory.ts +++ b/packages/contract/src/contract-factory.ts @@ -1,7 +1,13 @@ import { Interface } from '@fuel-ts/abi-coder'; import type { JsonAbi, InputValue } from '@fuel-ts/abi-coder'; +import type { + Account, + CreateTransactionRequestLike, + Provider, + TransactionResult, + TransactionType, +} from '@fuel-ts/account'; import { CreateTransactionRequest } from '@fuel-ts/account'; -import type { Account, CreateTransactionRequestLike, Provider } from '@fuel-ts/account'; import { randomBytes } from '@fuel-ts/crypto'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { BytesLike } from '@fuel-ts/interfaces'; @@ -21,6 +27,15 @@ export type DeployContractOptions = { configurableConstants?: { [name: string]: unknown }; } & CreateTransactionRequestLike; +export type DeployContractResult = { + transactionId: string; + contractId: string; + waitForResult: () => Promise<{ + contract: TContract; + transactionResult: TransactionResult; + }>; +}; + /** * `ContractFactory` provides utilities for deploying and configuring contracts. */ @@ -131,40 +146,24 @@ export default class ContractFactory { * @param deployContractOptions - Options for deploying the contract. * @returns A promise that resolves to the deployed contract instance. */ - async deployContract(deployContractOptions: DeployContractOptions = {}) { - if (!this.account) { - throw new FuelError(ErrorCode.ACCOUNT_REQUIRED, 'Cannot deploy Contract without account.'); - } - - const { configurableConstants } = deployContractOptions; - - if (configurableConstants) { - this.setConfigurableConstants(configurableConstants); - } - - const { contractId, transactionRequest } = this.createTransactionRequest(deployContractOptions); - - const txCost = await this.account.provider.getTransactionCost(transactionRequest); + async deployContract( + deployContractOptions: DeployContractOptions = {} + ): Promise> { + const { contractId, transactionRequest } = await this.prepareDeploy(deployContractOptions); + const account = this.getAccount(); + + const transactionResponse = await account.sendTransaction(transactionRequest, { + awaitExecution: false, + }); - const { maxFee: setMaxFee } = deployContractOptions; + const waitForResult = async () => { + const transactionResult = await transactionResponse.waitForResult(); + const contract = new Contract(contractId, this.interface, account) as TContract; - if (isDefined(setMaxFee)) { - if (txCost.maxFee.gt(setMaxFee)) { - throw new FuelError( - ErrorCode.MAX_FEE_TOO_LOW, - `Max fee '${deployContractOptions.maxFee}' is lower than the required: '${txCost.maxFee}'.` - ); - } - } else { - transactionRequest.maxFee = txCost.maxFee; - } - - await this.account.fund(transactionRequest, txCost); - await this.account.sendTransaction(transactionRequest, { - awaitExecution: true, - }); + return { contract, transactionResult }; + }; - return new Contract(contractId, this.interface, this.account); + return { waitForResult, contractId, transactionId: transactionResponse.id }; } /** @@ -202,4 +201,45 @@ export default class ContractFactory { ); } } + + private getAccount(): Account { + if (!this.account) { + throw new FuelError(ErrorCode.ACCOUNT_REQUIRED, 'Account not assigned to contract.'); + } + return this.account; + } + + private async prepareDeploy(deployContractOptions: DeployContractOptions) { + const { configurableConstants } = deployContractOptions; + + if (configurableConstants) { + this.setConfigurableConstants(configurableConstants); + } + + const { contractId, transactionRequest } = this.createTransactionRequest(deployContractOptions); + + const account = this.getAccount(); + + const txCost = await account.provider.getTransactionCost(transactionRequest); + + const { maxFee: setMaxFee } = deployContractOptions; + + if (isDefined(setMaxFee)) { + if (txCost.maxFee.gt(setMaxFee)) { + throw new FuelError( + ErrorCode.MAX_FEE_TOO_LOW, + `Max fee '${deployContractOptions.maxFee}' is lower than the required: '${txCost.maxFee}'.` + ); + } + } else { + transactionRequest.maxFee = txCost.maxFee; + } + + await account.fund(transactionRequest, txCost); + + return { + contractId, + transactionRequest, + }; + } } diff --git a/packages/contract/src/index.ts b/packages/contract/src/index.ts index 562e35cd034..f549c0c354c 100644 --- a/packages/contract/src/index.ts +++ b/packages/contract/src/index.ts @@ -1,4 +1,8 @@ -export { default as ContractFactory, DeployContractOptions } from './contract-factory'; +export { + default as ContractFactory, + DeployContractOptions, + DeployContractResult, +} from './contract-factory'; /** * @hidden */ diff --git a/packages/contract/src/test-utils/launch-test-node.ts b/packages/contract/src/test-utils/launch-test-node.ts index adae1cf42de..b35f833190f 100644 --- a/packages/contract/src/test-utils/launch-test-node.ts +++ b/packages/contract/src/test-utils/launch-test-node.ts @@ -6,20 +6,19 @@ import type { } from '@fuel-ts/account/test-utils'; import { FuelError } from '@fuel-ts/errors'; import type { BytesLike } from '@fuel-ts/interfaces'; -import type { Contract } from '@fuel-ts/program'; import type { SnapshotConfigs } from '@fuel-ts/utils'; import { readFileSync } from 'fs'; import * as path from 'path'; import { mergeDeepRight } from 'ramda'; -import type { DeployContractOptions } from '../contract-factory'; +import type { DeployContractOptions, DeployContractResult } from '../contract-factory'; export interface ContractDeployer { deployContract( bytecode: BytesLike, wallet: Account, options?: DeployContractOptions - ): Promise; + ): Promise; } export interface DeployContractConfig { @@ -49,7 +48,9 @@ export interface LaunchTestNodeOptions = { - [K in keyof T]: Awaited>; + [K in keyof T]: Awaited< + ReturnType>['waitForResult']> + >['contract']; }; export interface LaunchTestNodeReturn extends SetupTestProviderAndWalletsReturn { @@ -152,13 +153,13 @@ export async function launchTestNode( try { for (let i = 0; i < configs.length; i++) { const config = configs[i]; - contracts.push( - await config.deployer.deployContract( - config.bytecode, - getWalletForDeployment(config, wallets), - config.options ?? {} - ) + const { waitForResult } = await config.deployer.deployContract( + config.bytecode, + getWalletForDeployment(config, wallets), + config.options ?? {} ); + const { contract } = await waitForResult(); + contracts.push(contract); } } catch (err) { cleanup(); diff --git a/packages/fuel-gauge/src/auth-testing.test.ts b/packages/fuel-gauge/src/auth-testing.test.ts index 0a15ee550f7..04d41810925 100644 --- a/packages/fuel-gauge/src/auth-testing.test.ts +++ b/packages/fuel-gauge/src/auth-testing.test.ts @@ -22,7 +22,8 @@ describe('Auth Testing', () => { ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - contractInstance = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + ({ contract: contractInstance } = await waitForResult()); }); it('can get is_caller_external', async () => { diff --git a/packages/fuel-gauge/src/configurable-contract.test.ts b/packages/fuel-gauge/src/configurable-contract.test.ts index d421bab9241..4213d39f942 100644 --- a/packages/fuel-gauge/src/configurable-contract.test.ts +++ b/packages/fuel-gauge/src/configurable-contract.test.ts @@ -52,7 +52,8 @@ describe('Configurable Contract', () => { }); it('should assert default values', async () => { - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_configurables().simulate(); @@ -76,7 +77,10 @@ describe('Configurable Contract', () => { expect(defaultValues.U8).not.toBe(configurableConstants.U8); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_u8().simulate(); @@ -90,7 +94,10 @@ describe('Configurable Contract', () => { expect(defaultValues.U16).not.toBe(configurableConstants.U16); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_u16().simulate(); @@ -104,7 +111,10 @@ describe('Configurable Contract', () => { expect(defaultValues.U32).not.toBe(configurableConstants.U32); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_u32().simulate(); @@ -118,7 +128,10 @@ describe('Configurable Contract', () => { expect(defaultValues.U64).not.toBe(configurableConstants.U64); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_u64().simulate(); @@ -132,7 +145,10 @@ describe('Configurable Contract', () => { expect(defaultValues.BOOL).not.toBe(configurableConstants.BOOL); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_bool().simulate(); @@ -146,7 +162,10 @@ describe('Configurable Contract', () => { expect(defaultValues.B256).not.toBe(configurableConstants.B256); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_b256().simulate(); @@ -160,7 +179,10 @@ describe('Configurable Contract', () => { expect(defaultValues.ENUM).not.toBe(configurableConstants.ENUM); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_enum().simulate(); @@ -177,7 +199,10 @@ describe('Configurable Contract', () => { expect(defaultValues.ARRAY).not.toStrictEqual(configurableConstants.ARRAY); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_array().simulate(); @@ -191,7 +216,10 @@ describe('Configurable Contract', () => { expect(defaultValues.STR_4).not.toBe(configurableConstants.STR_4); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_str4().simulate(); @@ -205,7 +233,10 @@ describe('Configurable Contract', () => { expect(defaultValues.TUPLE).not.toStrictEqual(configurableConstants.TUPLE); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_tuple().simulate(); @@ -223,7 +254,10 @@ describe('Configurable Contract', () => { expect(defaultValues.STRUCT_1).not.toStrictEqual(configurableConstants.STRUCT_1); - const contract = await factory.deployContract({ configurableConstants }); + const { waitForResult } = await factory.deployContract({ + configurableConstants, + }); + const { contract } = await waitForResult(); const { value } = await contract.functions.echo_struct().simulate(); diff --git a/packages/fuel-gauge/src/contract-factory.test.ts b/packages/fuel-gauge/src/contract-factory.test.ts index f5facc38608..46a2c970da4 100644 --- a/packages/fuel-gauge/src/contract-factory.test.ts +++ b/packages/fuel-gauge/src/contract-factory.test.ts @@ -30,30 +30,32 @@ describe('Contract Factory', () => { it('Creates a factory from inputs that can return call results', async () => { const factory = await createContractFactory(); - const contact = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); - expect(contact.interface).toBeInstanceOf(Interface); + expect(contract.interface).toBeInstanceOf(Interface); - const { value: valueInitial } = await contact.functions.initialize_counter(41).call(); + const { value: valueInitial } = await contract.functions.initialize_counter(41).call(); expect(valueInitial.toHex()).toEqual(toHex(41)); - const { value } = await contact.functions.increment_counter(1).call(); + const { value } = await contract.functions.increment_counter(1).call(); expect(value.toHex()).toEqual(toHex(42)); - const { value: value2 } = await contact.functions.increment_counter(1).dryRun(); + const { value: value2 } = await contract.functions.increment_counter(1).dryRun(); expect(value2.toHex()).toEqual(toHex(43)); }); it('Creates a factory from inputs that can return transaction results', async () => { const factory = await createContractFactory(); - const contact = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); - expect(contact.interface).toBeInstanceOf(Interface); + expect(contract.interface).toBeInstanceOf(Interface); - await contact.functions.initialize_counter(100).call(); + await contract.functions.initialize_counter(100).call(); - const { transactionResult } = await contact.functions.increment_counter(1).call(); + const { transactionResult } = await contract.functions.increment_counter(1).call(); expect(transactionResult).toEqual({ blockId: expect.stringMatching(/^0x/), receipts: expect.arrayContaining([expect.any(Object)]), @@ -84,7 +86,7 @@ describe('Contract Factory', () => { }); expect(transactionResult.gasUsed.toNumber()).toBeGreaterThan(0); - const { callResult } = await contact.functions.increment_counter(1).dryRun(); + const { callResult } = await contract.functions.increment_counter(1).dryRun(); expect(callResult).toMatchObject({ receipts: expect.arrayContaining([expect.any(Object)]), }); @@ -93,7 +95,8 @@ describe('Contract Factory', () => { it('Creates a factory from inputs that can prepare call data', async () => { const factory = await createContractFactory(); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const prepared = contract.functions.increment_counter(1).getCallConfig(); expect(prepared).toEqual({ @@ -126,9 +129,10 @@ describe('Contract Factory', () => { it('Creates a contract with initial storage fixed var names', async () => { const factory = await createContractFactory(); - const contract = await factory.deployContract({ + const { waitForResult } = await factory.deployContract({ storageSlots, }); + const { contract } = await waitForResult(); const { value: var1 } = await contract.functions.return_var1().call(); expect(var1.toHex()).toEqual(toHex(0)); @@ -155,13 +159,14 @@ describe('Contract Factory', () => { const factory = await createContractFactory(); const b256 = '0x626f0c36909faecc316056fca8be684ab0cd06afc63247dc008bdf9e433f927a'; - const contact = await factory.deployContract({ + const { waitForResult } = await factory.deployContract({ storageSlots: [ { key: '0x0000000000000000000000000000000000000000000000000000000000000001', value: b256 }, ], }); + const { contract } = await waitForResult(); - const { value: vB256 } = await contact.functions.return_b256().simulate(); + const { value: vB256 } = await contract.functions.return_b256().simulate(); expect(vB256).toEqual(b256); }); @@ -169,12 +174,13 @@ describe('Contract Factory', () => { const factory = await createContractFactory(); const b256 = '0x626f0c36909faecc316056fca8be684ab0cd06afc63247dc008bdf9e433f927a'; - const contract = await factory.deployContract({ + const { waitForResult } = await factory.deployContract({ storageSlots: [ ...storageSlots, // initializing from storage_slots.json { key: '0000000000000000000000000000000000000000000000000000000000000001', value: b256 }, // Initializing manual value ], }); + const { contract } = await waitForResult(); const { value: var1 } = await contract.functions.return_var1().call(); expect(var1.toHex()).toEqual(toHex(0)); diff --git a/packages/fuel-gauge/src/contract.test.ts b/packages/fuel-gauge/src/contract.test.ts index b11e5217097..d074f6068e7 100644 --- a/packages/fuel-gauge/src/contract.test.ts +++ b/packages/fuel-gauge/src/contract.test.ts @@ -801,7 +801,8 @@ describe('Contract', () => { ]); const factory = new ContractFactory(contractBytecode, abi, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const vector = [5, 4, 3, 2, 1]; @@ -963,7 +964,8 @@ describe('Contract', () => { const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const receiver = Wallet.generate({ provider }); const amountToTransfer = 300; @@ -995,7 +997,8 @@ describe('Contract', () => { const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const receiver1 = Wallet.generate({ provider }); const receiver2 = Wallet.generate({ provider }); @@ -1035,7 +1038,9 @@ describe('Contract', () => { const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + + const { contract } = await waitForResult(); await expectToThrowFuelError( async () => { @@ -1163,7 +1168,8 @@ describe('Contract', () => { const factory = new ContractFactory(binHexlified, abiContents, wallet); - const storageContract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract: storageContract } = await waitForResult(); const initialCounterValue = 20; @@ -1192,7 +1198,8 @@ describe('Contract', () => { const wallet = await generateTestWallet(provider, [[350_000, baseAssetId]]); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const storageContract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract: storageContract } = await waitForResult(); const gasLimit = 200_000; const maxFee = 100_000; diff --git a/packages/fuel-gauge/src/dry-run-multiple-txs.test.ts b/packages/fuel-gauge/src/dry-run-multiple-txs.test.ts index 0376c567e46..338ba5061ae 100644 --- a/packages/fuel-gauge/src/dry-run-multiple-txs.test.ts +++ b/packages/fuel-gauge/src/dry-run-multiple-txs.test.ts @@ -47,26 +47,31 @@ describe('dry-run-multiple-txs', () => { const deployContracts = async () => { const revertFactory = new ContractFactory(binRevert, abiRevert, wallet); - const revertContract = await revertFactory.deployContract({ + let { waitForResult } = await revertFactory.deployContract({ maxFee: 70_000, }); + const { contract: revertContract } = await waitForResult(); const multiTokenFactory = new ContractFactory(binMultiToken, abiMultiToken, wallet); - const multiTokenContract = await multiTokenFactory.deployContract({ + ({ waitForResult } = await multiTokenFactory.deployContract({ maxFee: 70_000, - }); + })); + const { contract: multiTokenContract } = await waitForResult(); const logFactory = new ContractFactory(binLog, abiLog, wallet); - const logContract = await logFactory.deployContract({ + ({ waitForResult } = await logFactory.deployContract({ maxFee: 70_000, - }); + })); + const { contract: logContract } = await waitForResult(); + const logOtherFactory = new ContractFactory(binLogOther, abiLogOther, wallet); - const logOtherContract = await logOtherFactory.deployContract({ + ({ waitForResult } = await logOtherFactory.deployContract({ maxFee: 70_000, - }); + })); + const { contract: logOtherContract } = await waitForResult(); return { revertContract, multiTokenContract, logContract, logOtherContract }; }; @@ -74,9 +79,10 @@ describe('dry-run-multiple-txs', () => { it('should properly dry-run multiple TXs requests', async () => { const revertFactory = new ContractFactory(binRevert, abiRevert, wallet); - const revertContract = await revertFactory.deployContract({ + const { waitForResult } = await revertFactory.deployContract({ maxFee: 70_000, }); + const { contract: revertContract } = await waitForResult(); const resources = await wallet.getResourcesToSpend([[500_000, baseAssetId]]); diff --git a/packages/fuel-gauge/src/fee.test.ts b/packages/fuel-gauge/src/fee.test.ts index 4b61b265ad4..b7f95b33fa1 100644 --- a/packages/fuel-gauge/src/fee.test.ts +++ b/packages/fuel-gauge/src/fee.test.ts @@ -53,7 +53,8 @@ describe('Fee', () => { ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); // minting coins let balanceBefore = await wallet.getBalance(); @@ -177,7 +178,8 @@ describe('Fee', () => { ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const balanceBefore = await wallet.getBalance(); @@ -204,7 +206,8 @@ describe('Fee', () => { ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const balanceBefore = await wallet.getBalance(); @@ -235,7 +238,8 @@ describe('Fee', () => { ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); const subId = '0x4a778acfad1abc155a009dc976d2cf0db6197d3d360194d74b1fb92b96986b00'; diff --git a/packages/fuel-gauge/src/predicate/utils/predicate/setupContract.ts b/packages/fuel-gauge/src/predicate/utils/predicate/setupContract.ts index f7d4e13de4d..4e2e43cec27 100644 --- a/packages/fuel-gauge/src/predicate/utils/predicate/setupContract.ts +++ b/packages/fuel-gauge/src/predicate/utils/predicate/setupContract.ts @@ -19,7 +19,8 @@ const deployContract = async ( if (contractInstance && useCache) { return contractInstance; } - contractInstance = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + ({ contract: contractInstance } = await waitForResult()); return contractInstance; }; diff --git a/packages/fuel-gauge/src/reentrant-contract-calls.test.ts b/packages/fuel-gauge/src/reentrant-contract-calls.test.ts index 36cfb84d0aa..1d475fb91e5 100644 --- a/packages/fuel-gauge/src/reentrant-contract-calls.test.ts +++ b/packages/fuel-gauge/src/reentrant-contract-calls.test.ts @@ -23,10 +23,12 @@ describe('Reentrant Contract Calls', () => { wallet = await generateTestWallet(provider, [[500_000, baseAssetId]]); const factoryBar = new ContractFactory(bar.binHexlified, bar.abiContents, wallet); - barContract = await factoryBar.deployContract(); + let { waitForResult } = await factoryBar.deployContract(); + ({ contract: barContract } = await waitForResult()); const factoryFoo = new ContractFactory(foo.binHexlified, foo.abiContents, wallet); - fooContract = await factoryFoo.deployContract(); + ({ waitForResult } = await factoryFoo.deployContract()); + ({ contract: fooContract } = await waitForResult()); }); it('should ensure the SDK returns the proper value for a reentrant call', async () => { @@ -64,12 +66,14 @@ describe('Reentrant Contract Calls', () => { }); it('should ensure the SDK returns the proper value for a reentrant call on multi-call', async () => { - const storageContract = await new ContractFactory( + const { waitForResult } = await new ContractFactory( storageTest.binHexlified, storageTest.abiContents, wallet ).deployContract({ storageSlots: storageTest.storageSlots }); + const { contract: storageContract } = await waitForResult(); + const reentrantCall = fooContract.functions.foo( { bits: fooContract.id.toB256() }, { bits: barContract.id.toB256() } diff --git a/packages/fuel-gauge/src/revert-error.test.ts b/packages/fuel-gauge/src/revert-error.test.ts index a6d50f60d9c..6f2ee20e1a5 100644 --- a/packages/fuel-gauge/src/revert-error.test.ts +++ b/packages/fuel-gauge/src/revert-error.test.ts @@ -25,7 +25,8 @@ describe('Revert Error Testing', () => { ); const factory = new ContractFactory(bytecode, FactoryAbi, wallet); - contractInstance = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + ({ contract: contractInstance } = await waitForResult()); }); it('can pass require checks [valid]', async () => { @@ -180,7 +181,8 @@ describe('Revert Error Testing', () => { ); const factory = new ContractFactory(tokenBytecode, tokenAbi, wallet); - const tokenContract = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + const { contract: tokenContract } = await waitForResult(); const addresses = [ { bits: getRandomB256() }, diff --git a/packages/fuel-gauge/src/storage-test-contract.test.ts b/packages/fuel-gauge/src/storage-test-contract.test.ts index 09fec504d31..bbd6abe9717 100644 --- a/packages/fuel-gauge/src/storage-test-contract.test.ts +++ b/packages/fuel-gauge/src/storage-test-contract.test.ts @@ -19,9 +19,10 @@ const setup = async () => { // #context import storageSlots from '../your-sway-project/out/debug/your-sway-project-storage_slots.json'; const factory = new ContractFactory(bytecode, abi, wallet); - const contract = await factory.deployContract({ + const { waitForResult } = await factory.deployContract({ storageSlots, }); + const { contract } = await waitForResult(); // #endregion contract-deployment-storage-slots return contract; @@ -54,7 +55,7 @@ describe('StorageTestContract', () => { const wallet = await generateTestWallet(provider, [[500_000, baseAssetId]]); const factory = new ContractFactory(bytecode, abi, wallet); // #region contract-deployment-storage-slots-inline - const contract = await factory.deployContract({ + const { waitForResult } = await factory.deployContract({ storageSlots: [ { key: '02dac99c283f16bc91b74f6942db7f012699a2ad51272b15207b9cc14a70dbae', @@ -78,6 +79,7 @@ describe('StorageTestContract', () => { }, ], }); + const { contract } = await waitForResult(); // #endregion contract-deployment-storage-slots-inline const { value: initializeResult } = await contract.functions.initialize_counter(1300).call(); expect(initializeResult.toHex()).toEqual(toHex(1300)); diff --git a/packages/fuel-gauge/src/token-test-contract.test.ts b/packages/fuel-gauge/src/token-test-contract.test.ts index 49b204cd936..84d0ee5a98b 100644 --- a/packages/fuel-gauge/src/token-test-contract.test.ts +++ b/packages/fuel-gauge/src/token-test-contract.test.ts @@ -18,8 +18,8 @@ const setup = async () => { // Deploy contract const factory = new ContractFactory(bytecode, abi, wallet); - const contract = await factory.deployContract(); - + const { waitForResult } = await factory.deployContract(); + const { contract } = await waitForResult(); return contract; }; diff --git a/packages/fuel-gauge/src/utils.ts b/packages/fuel-gauge/src/utils.ts index 853f2ab76cb..9e174bcc9a8 100644 --- a/packages/fuel-gauge/src/utils.ts +++ b/packages/fuel-gauge/src/utils.ts @@ -5,7 +5,7 @@ import { ASSET_A, generateTestWallet } from 'fuels/test-utils'; import { join } from 'path'; let contractInstance: Contract; -const deployContract = async ( +const deployContract = async ( factory: ContractFactory, provider: Provider, useCache: boolean = true @@ -13,7 +13,8 @@ const deployContract = async ( if (contractInstance && useCache) { return contractInstance; } - contractInstance = await factory.deployContract(); + const { waitForResult } = await factory.deployContract(); + ({ contract: contractInstance } = await waitForResult()); return contractInstance; }; @@ -37,7 +38,7 @@ export type SetupConfig = { cache?: boolean; }; -export const setup = async ({ +export const setup = async ({ contractBytecode, abi, cache, @@ -45,8 +46,8 @@ export const setup = async ({ // Create wallet const wallet = await createWallet(); const factory = new ContractFactory(contractBytecode, abi, wallet); - const contract = await deployContract(factory, wallet.provider, cache); - return contract as T; + const contract = await deployContract(factory, wallet.provider, cache); + return contract as TContract; }; export const createSetupConfig = diff --git a/packages/fuels/src/cli/commands/deploy/deployContract.ts b/packages/fuels/src/cli/commands/deploy/deployContract.ts index e0f285049fd..4b342e12438 100644 --- a/packages/fuels/src/cli/commands/deploy/deployContract.ts +++ b/packages/fuels/src/cli/commands/deploy/deployContract.ts @@ -25,6 +25,8 @@ export async function deployContract( const abi = JSON.parse(readFileSync(abiPath, 'utf-8')); const contractFactory = new ContractFactory(bytecode, abi, wallet); - const contract = await contractFactory.deployContract(deployConfig); + const { waitForResult } = await contractFactory.deployContract(deployConfig); + const { contract } = await waitForResult(); + return contract.id.toB256(); }