diff --git a/.changeset/kind-maps-switch.md b/.changeset/kind-maps-switch.md new file mode 100644 index 00000000000..81614480b58 --- /dev/null +++ b/.changeset/kind-maps-switch.md @@ -0,0 +1,16 @@ +--- +"@fuel-ts/abi-coder": minor +"@fuel-ts/abi-typegen": minor +"@fuel-ts/account": minor +"@fuel-ts/contract": minor +"@fuel-ts/forc": minor +"@fuel-ts/fuel-core": minor +"fuels": minor +"@fuel-ts/interfaces": minor +"@fuel-ts/program": minor +"@fuel-ts/script": minor +"@fuel-ts/transactions": minor +"@fuel-ts/versions": minor +--- + +chore!: upgrade `fuel-core` to `0.23.0` diff --git a/.changeset/tidy-olives-dance.md b/.changeset/tidy-olives-dance.md new file mode 100644 index 00000000000..6e830b55472 --- /dev/null +++ b/.changeset/tidy-olives-dance.md @@ -0,0 +1,7 @@ +--- +"@fuel-ts/abi-typegen": patch +"@fuel-ts/forc": patch +"@fuel-ts/versions": patch +--- + +chore: upgrading `forc` to `0.51.1` diff --git a/apps/demo-fuels/fuels.config.full.ts b/apps/demo-fuels/fuels.config.full.ts index 839d1588b2d..16d31e6a8b4 100644 --- a/apps/demo-fuels/fuels.config.full.ts +++ b/apps/demo-fuels/fuels.config.full.ts @@ -30,8 +30,8 @@ export default createConfig({ // #endregion privateKey // #region providerUrl - // Default: http://127.0.0.1:4000/graphql - providerUrl: 'http://network:port/graphql', + // Default: http://127.0.0.1:4000/v1/graphql + providerUrl: 'http://network:port/v1/graphql', // #endregion providerUrl // #region chainConfig @@ -70,7 +70,6 @@ export default createConfig({ } return { - gasPrice: 1, storageSlots: [ { key: '0x..', @@ -112,8 +111,6 @@ export const simpleDeployConfig = createConfig({ workspace: './sway-programs', output: './src/sway-programs-api', // #region deployConfig-obj - deployConfig: { - gasPrice: 1, - }, + deployConfig: {}, // #endregion deployConfig-obj }); diff --git a/apps/demo-fuels/src/index.test.ts b/apps/demo-fuels/src/index.test.ts index 701ef9a4398..9233405bd88 100644 --- a/apps/demo-fuels/src/index.test.ts +++ b/apps/demo-fuels/src/index.test.ts @@ -7,30 +7,22 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; import { safeExec } from '@fuel-ts/errors/test-utils'; -import type { BN } from 'fuels'; import { ContractFactory, Provider, toHex, BaseAssetId, Wallet, FUEL_NETWORK_URL } from 'fuels'; import { SampleAbi__factory } from './sway-programs-api'; import bytecode from './sway-programs-api/contracts/SampleAbi.hex'; -let gasPrice: BN; - /** * @group node */ describe('ExampleContract', () => { - beforeAll(async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); - }); - it('should return the input', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); // Deploy const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, wallet); - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); // Call const { value } = await contract.functions.return_input(1337).call(); @@ -49,7 +41,7 @@ describe('ExampleContract', () => { const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); // Deploy - const contract = await SampleAbi__factory.deployContract(bytecode, wallet, { gasPrice }); + const contract = await SampleAbi__factory.deployContract(bytecode, wallet); // Call const { value } = await contract.functions.return_input(1337).call(); @@ -64,7 +56,7 @@ describe('ExampleContract', () => { const unfundedWallet = Wallet.generate({ provider }); const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, fundedWallet); - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); const contractInstance = SampleAbi__factory.connect(contract.id, unfundedWallet); const { error } = await safeExec(() => @@ -80,7 +72,7 @@ describe('ExampleContract', () => { const unfundedWallet = Wallet.generate({ provider }); const factory = new ContractFactory(bytecode, SampleAbi__factory.abi, fundedWallet); - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); const contractInstance = SampleAbi__factory.connect(contract.id, unfundedWallet); await expect(contractInstance.functions.return_input(1337).dryRun()).resolves.not.toThrow(); @@ -89,7 +81,7 @@ 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, { gasPrice }); + const depoloyed = await SampleAbi__factory.deployContract(bytecode, wallet); const contractsIds = { sample: depoloyed.id, }; diff --git a/apps/demo-typegen/src/demo.test.ts b/apps/demo-typegen/src/demo.test.ts index 320c65bc6aa..07d962bf064 100644 --- a/apps/demo-typegen/src/demo.test.ts +++ b/apps/demo-typegen/src/demo.test.ts @@ -1,7 +1,6 @@ // #region Testing-in-ts-ts import { generateTestWallet } from '@fuel-ts/account/test-utils'; import { safeExec } from '@fuel-ts/errors/test-utils'; -import type { BN } from 'fuels'; import { ContractFactory, Provider, @@ -20,16 +19,10 @@ import type { PredicateAbiInputs } from './predicate-types'; import { PredicateAbi__factory } from './predicate-types'; import { ScriptAbi__factory } from './script-types'; -let gasPrice: BN; - /** * @group node */ describe('ExampleContract', () => { - beforeAll(async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); - }); it('with imported storage slots', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); @@ -39,7 +32,6 @@ describe('ExampleContract', () => { const contract = await DemoContractAbi__factory.deployContract(bytecode, wallet, { storageSlots, - gasPrice, }); // #endregion typegen-demo-contract-storage-slots @@ -51,7 +43,7 @@ describe('ExampleContract', () => { // Deploy const factory = new ContractFactory(bytecode, DemoContractAbi__factory.abi, wallet); - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); const contractId = contract.id; // Call @@ -79,7 +71,7 @@ describe('ExampleContract', () => { // #context import bytecode from './types/DemoContractAbi.hex'; // Deploy - const contract = await DemoContractAbi__factory.deployContract(bytecode, wallet, { gasPrice }); + const contract = await DemoContractAbi__factory.deployContract(bytecode, wallet); // #endregion typegen-demo-contract-factory-deploy // Call @@ -97,7 +89,7 @@ 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({ gasPrice }); + const contract = await factory.deployContract(); const contractInstance = DemoContractAbi__factory.connect(contract.id, unfundedWallet); const { error } = await safeExec(() => contractInstance.functions.return_input(1337).simulate()); @@ -111,7 +103,7 @@ 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({ gasPrice }); + const contract = await factory.deployContract(); const contractInstance = DemoContractAbi__factory.connect(contract.id, unfundedWallet); await expect(contractInstance.functions.return_input(1337).dryRun()).resolves.not.toThrow(); @@ -150,10 +142,7 @@ test('Example predicate', async () => { const initialPredicateBalance = await predicate.getBalance(); // Then we are transferring some coins from the predicate to a random address (receiver) - const tx2 = await predicate.transfer(receiver.address, 50_000, BaseAssetId, { - gasPrice: provider.getGasConfig().minGasPrice, - gasLimit: 50, - }); + const tx2 = await predicate.transfer(receiver.address, 50_000, BaseAssetId); await tx2.wait(); expect((await receiver.getBalance()).toNumber()).toEqual(50_000); diff --git a/apps/docs-snippets/src/guide/contracts/call-parameters.test.ts b/apps/docs-snippets/src/guide/contracts/call-parameters.test.ts index 8ce6c7e7623..38ef1c5ffae 100644 --- a/apps/docs-snippets/src/guide/contracts/call-parameters.test.ts +++ b/apps/docs-snippets/src/guide/contracts/call-parameters.test.ts @@ -1,4 +1,4 @@ -import type { Contract, Provider } from 'fuels'; +import type { Contract } from 'fuels'; import { BN, BaseAssetId } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; @@ -9,10 +9,8 @@ import { createAndDeployContractFromProject } from '../../utils'; */ describe(__filename, () => { let contract: Contract; - let provider: Provider; beforeAll(async () => { contract = await createAndDeployContractFromProject(DocSnippetProjectsEnum.RETURN_CONTEXT); - provider = contract.provider; }); it('should successfully execute contract call with forwarded amount', async () => { @@ -32,7 +30,6 @@ describe(__filename, () => { it('should throw error due not enough gas', async () => { // #region call-params-2 - const { minGasPrice } = provider.getGasConfig(); await expect( contract.functions @@ -41,7 +38,6 @@ describe(__filename, () => { forward: [10, BaseAssetId], gasLimit: 1, }) - .txParams({ gasPrice: minGasPrice }) .call() ).rejects.toThrow(/Gas limit '1' is lower than the required: /); // #endregion call-params-2 @@ -49,7 +45,6 @@ describe(__filename, () => { it('should successfully execute transaction with `txParams` and `callParams`', async () => { // #region call-params-3 - const { minGasPrice } = provider.getGasConfig(); const amountToForward = 10; const contractCallGasLimit = 100; const transactionGasLimit = 3_000_000; @@ -62,17 +57,12 @@ describe(__filename, () => { }) .txParams({ gasLimit: transactionGasLimit, - gasPrice: minGasPrice, }) .call(); - const { - transactionResult: { transaction }, - value, - } = result; + const { value } = result; expect(new BN(value).toNumber()).toBe(10); - expect(new BN(transaction.scriptGasLimit).toNumber()).toBe(transactionGasLimit); // #endregion call-params-3 }); }); 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 1f62069695b..5fe6b9d181a 100644 --- a/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts +++ b/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts @@ -1,4 +1,4 @@ -import type { Provider, WalletUnlocked } from 'fuels'; +import type { WalletUnlocked } from 'fuels'; import { ContractFactory } from 'fuels'; import { @@ -28,10 +28,8 @@ describe('configurable-constants', () => { }, }; - let provider: Provider; beforeAll(async () => { wallet = await getTestWallet(); - provider = wallet.provider; }); it('should successfully set new values for all configurable constants', async () => { @@ -49,11 +47,8 @@ describe('configurable-constants', () => { const factory = new ContractFactory(bin, abi, wallet); - const { minGasPrice } = provider.getGasConfig(); - const contract = await factory.deployContract({ configurableConstants, - gasPrice: minGasPrice, }); // #endregion configurable-constants-2 @@ -73,11 +68,8 @@ describe('configurable-constants', () => { const factory = new ContractFactory(bin, abi, wallet); - const { minGasPrice } = provider.getGasConfig(); - const contract = await factory.deployContract({ configurableConstants, - gasPrice: minGasPrice, }); // #endregion configurable-constants-3 @@ -99,12 +91,9 @@ describe('configurable-constants', () => { const factory = new ContractFactory(bin, abi, wallet); - const { minGasPrice } = provider.getGasConfig(); - await expect( factory.deployContract({ configurableConstants, - gasPrice: minGasPrice, }) ).rejects.toThrowError(); // #endregion configurable-constants-4 diff --git a/apps/docs-snippets/src/guide/contracts/cost-estimation.test.ts b/apps/docs-snippets/src/guide/contracts/cost-estimation.test.ts index 8bb01d25d04..6b1a6836221 100644 --- a/apps/docs-snippets/src/guide/contracts/cost-estimation.test.ts +++ b/apps/docs-snippets/src/guide/contracts/cost-estimation.test.ts @@ -26,7 +26,7 @@ describe(__filename, () => { expect(cost.maxFee).toBeDefined(); expect(cost.gasPrice).toBeDefined(); expect(cost.gasUsed).toBeDefined(); - expect(cost.minGasPrice).toBeDefined(); + expect(cost.gasPrice).toBeDefined(); // #endregion cost-estimation-1 }); @@ -48,7 +48,7 @@ describe(__filename, () => { expect(cost.maxFee).toBeDefined(); expect(cost.gasPrice).toBeDefined(); expect(cost.gasUsed).toBeDefined(); - expect(cost.minGasPrice).toBeDefined(); + expect(cost.gasPrice).toBeDefined(); // #endregion cost-estimation-2 }); }); 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 15b277a6b79..9517d093aa5 100644 --- a/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts +++ b/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts @@ -44,9 +44,7 @@ describe(__filename, () => { // #region contract-setup-3 const factory = new ContractFactory(byteCode, abi, wallet); - const { minGasPrice: gasPrice } = wallet.provider.getGasConfig(); - - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); // #endregion contract-setup-3 // #region 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 06c3878a660..1cb30bf77f4 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 @@ -1,4 +1,4 @@ -import type { Contract, Provider, WalletUnlocked } from 'fuels'; +import type { Contract, WalletUnlocked } from 'fuels'; import { BN, ContractFactory } from 'fuels'; import { @@ -14,12 +14,9 @@ describe(__filename, () => { let wallet: WalletUnlocked; let simpleToken: Contract; let tokenDepositor: Contract; - let provider: Provider; beforeAll(async () => { wallet = await getTestWallet(); - provider = wallet.provider; - const { minGasPrice } = provider.getGasConfig(); const tokenArtifacts = getDocsSnippetsForcProject(DocSnippetProjectsEnum.SIMPLE_TOKEN); const depositorArtifacts = getDocsSnippetsForcProject(DocSnippetProjectsEnum.TOKEN_DEPOSITOR); @@ -28,13 +25,13 @@ describe(__filename, () => { tokenArtifacts.binHexlified, tokenArtifacts.abiContents, wallet - ).deployContract({ gasPrice: minGasPrice }); + ).deployContract(); tokenDepositor = await new ContractFactory( depositorArtifacts.binHexlified, depositorArtifacts.abiContents, wallet - ).deployContract({ gasPrice: minGasPrice }); + ).deployContract(); }); 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 124c53e3d66..d57d059d365 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,7 @@ describe(__filename, () => { beforeAll(async () => { wallet = await getTestWallet(); const factory = new ContractFactory(bin, abi, wallet); - const { minGasPrice: gasPrice } = wallet.provider.getGasConfig(); - contract = await factory.deployContract({ gasPrice }); + contract = await factory.deployContract(); 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 b22a7d88c95..394f2ed1f00 100644 --- a/apps/docs-snippets/src/guide/contracts/multicalls.test.ts +++ b/apps/docs-snippets/src/guide/contracts/multicalls.test.ts @@ -1,4 +1,4 @@ -import type { Contract, Provider } from 'fuels'; +import type { Contract } from 'fuels'; import { BaseAssetId, BN, ContractFactory } from 'fuels'; import { @@ -14,12 +14,9 @@ describe(__filename, () => { let echoContract: Contract; let counterContract: Contract; let contextContract: Contract; - let provider: Provider; beforeAll(async () => { const wallet = await getTestWallet(); - provider = wallet.provider; - const { minGasPrice: gasPrice } = provider.getGasConfig(); const counterArtifacts = getDocsSnippetsForcProject(DocSnippetProjectsEnum.COUNTER); const echoArtifacts = getDocsSnippetsForcProject(DocSnippetProjectsEnum.ECHO_VALUES); @@ -41,12 +38,11 @@ describe(__filename, () => { wallet ); - echoContract = await factory1.deployContract({ gasPrice }); + echoContract = await factory1.deployContract(); counterContract = await factory2.deployContract({ storageSlots: counterArtifacts.storageSlots, - gasPrice, }); - contextContract = await factory3.deployContract({ gasPrice }); + contextContract = await factory3.deployContract(); }); it('should successfully submit multiple calls from the same contract function', async () => { diff --git a/apps/docs-snippets/src/guide/contracts/transaction-parameters.test.ts b/apps/docs-snippets/src/guide/contracts/transaction-parameters.test.ts index dfc9aee8d35..736e0a64bc4 100644 --- a/apps/docs-snippets/src/guide/contracts/transaction-parameters.test.ts +++ b/apps/docs-snippets/src/guide/contracts/transaction-parameters.test.ts @@ -1,4 +1,4 @@ -import type { Contract, Provider } from 'fuels'; +import type { Contract } from 'fuels'; import { BN, PolicyType } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; @@ -9,33 +9,28 @@ import { createAndDeployContractFromProject } from '../../utils'; */ describe(__filename, () => { let contract: Contract; - let provider: Provider; beforeAll(async () => { contract = await createAndDeployContractFromProject(DocSnippetProjectsEnum.COUNTER); - provider = contract.provider; }); it('should successfully execute contract call with txParams', async () => { // #region transaction-parameters-2 - const { minGasPrice } = provider.getGasConfig(); - + // #region variable-outputs-1 + const tip = 1; const { transactionResult } = await contract.functions .increment_count(15) .txParams({ - gasLimit: 10_000, variableOutputs: 1, + tip, }) .call(); // #endregion transaction-parameters-2 const { transaction } = transactionResult; - const gasLimitPolicy = transaction.policies?.find( - (policy) => policy.type === PolicyType.GasPrice - ); + const gasLimitPolicy = transaction.policies?.find((policy) => policy.type === PolicyType.Tip); - expect(new BN(transaction.scriptGasLimit).toNumber()).toBe(10_000); - expect(new BN(gasLimitPolicy?.data).toNumber()).toBe(minGasPrice.toNumber()); + expect(new BN(gasLimitPolicy?.data).toNumber()).toBe(tip); }); it('should succesfully execute contract call without txParams', 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 f3b20ec1ea7..c4015db63bf 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 @@ -30,13 +30,11 @@ describe('Custom Transactions from Contract Calls', () => { senderWallet = await getTestWallet(); receiverWallet = Wallet.generate({ provider: senderWallet.provider }); const factory = new ContractFactory(binHexlified, abiContents, senderWallet); - const { minGasPrice: gasPrice } = senderWallet.provider.getGasConfig(); - contract = await factory.deployContract({ storageSlots, gasPrice }); + contract = await factory.deployContract({ storageSlots }); abi = abiContents; }); it('creates a custom transaction from a contract call', async () => { - const gasPrice = senderWallet.provider.getGasConfig().minGasPrice; const initialBalance = await receiverWallet.getBalance(BaseAssetId); expect(initialBalance.toNumber()).toBe(0); @@ -49,13 +47,11 @@ describe('Custom Transactions from Contract Calls', () => { // Create an invocation scope for the contract function you'd like to call in the transaction const scope = contractInstance.functions .increment_count(amountToRecipient) - .txParams({ gasPrice }); + .addTransfer(receiverWallet.address, amountToRecipient, BaseAssetId); // Fund the transaction await scope.fundWithRequiredCoins(); // Build a transaction request from the invocation scope const transactionRequest = await scope.getTransactionRequest(); - // Add coin output for the recipient - transactionRequest.addCoinOutput(receiverWallet.address, amountToRecipient, BaseAssetId); // Submit the transaction const response = await senderWallet.sendTransaction(transactionRequest); await response.waitForResult(); 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 aff3abc05f6..0a2ee65846f 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 @@ -23,8 +23,7 @@ describe(__filename, () => { ); provider = sender.provider; const factory = new ContractFactory(binHexlified, abiContents, sender); - const { minGasPrice } = sender.provider.getGasConfig(); - liquidityPoolContract = await factory.deployContract({ gasPrice: minGasPrice }); + liquidityPoolContract = await factory.deployContract(); }); it('deposit and withdraw cookbook guide', async () => { diff --git a/apps/docs-snippets/src/guide/cookbook/signing-transactions.test.ts b/apps/docs-snippets/src/guide/cookbook/signing-transactions.test.ts index b47e30d8a48..7bafcec99d7 100644 --- a/apps/docs-snippets/src/guide/cookbook/signing-transactions.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/signing-transactions.test.ts @@ -17,7 +17,6 @@ describe('Signing transactions', () => { let receiver: WalletUnlocked; let signer: WalletUnlocked; let provider: Provider; - let gasPrice: BN; const { abiContents: abiPredicate, binHexlified: binPredicate } = getDocsSnippetsForcProject( DocSnippetProjectsEnum.PREDICATE_SIGNING ); @@ -32,7 +31,6 @@ describe('Signing transactions', () => { }); provider = sender.provider; - ({ minGasPrice: gasPrice } = provider.getGasConfig()); }); beforeEach(() => { @@ -79,7 +77,7 @@ describe('Signing transactions', () => { await sender.transfer(predicate.address, 10_000, BaseAssetId); // Create the transaction request - const request = new ScriptTransactionRequest({ gasPrice, gasLimit: 10_000 }); + const request = new ScriptTransactionRequest(); request.addCoinOutput(receiver.address, amountToReceiver, BaseAssetId); // Get the predicate resources and add them and predicate data to the request @@ -89,19 +87,29 @@ describe('Signing transactions', () => { amount: amountToReceiver, }, ]); - request.addPredicateResources(resources, predicate); - const parsedRequest = predicate.populateTransactionPredicateData(request); - // Add witnesses including the signer - parsedRequest.addWitness('0x'); - await parsedRequest.addAccountWitnesses(signer); + request.addResources(resources); + + request.addWitness('0x'); + // Add witnesses including the signer // Estimate the predicate inputs - const { estimatedInputs } = await provider.getTransactionCost(parsedRequest); - parsedRequest.updatePredicateInputs(estimatedInputs); + const txCost = await provider.getTransactionCost(request, { + signatureCallback: (tx) => tx.addAccountWitnesses(signer), + resourcesOwner: predicate, + }); + + request.updatePredicateGasUsed(txCost.estimatedPredicates); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await predicate.fund(request, txCost); + + await request.addAccountWitnesses(signer); // Send the transaction - const res = await provider.sendTransaction(parsedRequest); + const res = await provider.sendTransaction(request); await res.waitForResult(); // #endregion multiple-signers-4 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 d9c428754fe..4c6f6f31fbf 100644 --- a/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts @@ -23,8 +23,7 @@ describe(__filename, () => { ); provider = sender.provider; const factory = new ContractFactory(binHexlified, abiContents, sender); - const { minGasPrice } = sender.provider.getGasConfig(); - deployedContract = await factory.deployContract({ gasPrice: minGasPrice }); + deployedContract = await factory.deployContract(); }); it('should successfully transfer asset to another account', async () => { diff --git a/apps/docs-snippets/src/guide/introduction/getting-started.test.ts b/apps/docs-snippets/src/guide/introduction/getting-started.test.ts index 6c876a27884..d69e092c026 100644 --- a/apps/docs-snippets/src/guide/introduction/getting-started.test.ts +++ b/apps/docs-snippets/src/guide/introduction/getting-started.test.ts @@ -7,32 +7,11 @@ import { FUEL_NETWORK_URL, FUEL_BETA_5_NETWORK_URL, Provider, Wallet, WalletUnlo describe('Getting started', () => { beforeAll(() => { // Avoids using the actual network. - vi.spyOn(Provider, 'create') - .mockImplementationOnce( - () => Provider.create(FUEL_NETWORK_URL) - ) - }) + vi.spyOn(Provider, 'create').mockImplementationOnce(() => Provider.create(FUEL_NETWORK_URL)); + }); - it('can connect to a local network', async () => { - // #region connecting-to-the-local-node - // #import { Provider, Wallet }; - - // Create a provider. - const LOCAL_FUEL_NETWORK = "http://127.0.0.1:4000/graphql" - const provider = await Provider.create(LOCAL_FUEL_NETWORK); - - // Create our wallet (with a private key). - const PRIVATE_KEY = 'a1447cd75accc6b71a976fd3401a1f6ce318d27ba660b0315ee6ac347bf39568'; - const wallet = Wallet.fromPrivateKey(PRIVATE_KEY, provider); - // #endregion connecting-to-the-local-node - - expect(provider).toBeTruthy(); - expect(provider).toBeInstanceOf(Provider); - expect(wallet).toBeTruthy(); - expect(wallet).toBeInstanceOf(WalletUnlocked); - }) - - it('can connect to testnet', async () => { + // TODO: remove skip from testnet test + it.skip('can connect to testnet', async () => { // #region connecting-to-the-testnet // #import { Provider, Wallet, FUEL_BETA_5_NETWORK_URL }; @@ -44,11 +23,30 @@ describe('Getting started', () => { const wallet = Wallet.fromPrivateKey(PRIVATE_KEY, provider); // Perform a balance check. - const balances = await wallet.getBalances() + const balances = await wallet.getBalances(); // [{ assetId: '0x..', amount: bn(..) }, ..] // #endregion connecting-to-the-testnet expect(balances).toBeTruthy(); expect(balances).toBeInstanceOf(Array); - }) -}) \ No newline at end of file + }); + + it('can connect to a local network', async () => { + // #region connecting-to-the-local-node + // #import { Provider, Wallet }; + + // Create a provider. + const LOCAL_FUEL_NETWORK = 'http://127.0.0.1:4000/graphql'; + const provider = await Provider.create(LOCAL_FUEL_NETWORK); + + // Create our wallet (with a private key). + const PRIVATE_KEY = 'a1447cd75accc6b71a976fd3401a1f6ce318d27ba660b0315ee6ac347bf39568'; + const wallet = Wallet.fromPrivateKey(PRIVATE_KEY, provider); + // #endregion connecting-to-the-local-node + + expect(provider).toBeTruthy(); + expect(provider).toBeInstanceOf(Provider); + expect(wallet).toBeTruthy(); + expect(wallet).toBeInstanceOf(WalletUnlocked); + }); +}); diff --git a/apps/docs-snippets/src/guide/predicates/predicate-with-configurable.test.ts b/apps/docs-snippets/src/guide/predicates/predicate-with-configurable.test.ts index 6d36031338c..c6b70453963 100644 --- a/apps/docs-snippets/src/guide/predicates/predicate-with-configurable.test.ts +++ b/apps/docs-snippets/src/guide/predicates/predicate-with-configurable.test.ts @@ -11,7 +11,6 @@ import { getTestWallet } from '../../utils'; */ describe(__filename, () => { let wallet: WalletUnlocked; - let gasPrice: BN; const { abiContents: abi, binHexlified: bin } = getDocsSnippetsForcProject( DocSnippetProjectsEnum.WHITELISTED_ADDRESS_PREDICATE @@ -19,7 +18,6 @@ describe(__filename, () => { beforeAll(async () => { wallet = await getTestWallet(); - ({ minGasPrice: gasPrice } = wallet.provider.getGasConfig()); }); it('should successfully tranfer to setted whitelisted address', async () => { @@ -37,9 +35,8 @@ describe(__filename, () => { }); // transferring funds to the predicate - const tx1 = await wallet.transfer(predicate.address, 500_000, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + const tx1 = await wallet.transfer(predicate.address, 1000, BaseAssetId, { + gasLimit: 100, }); await tx1.waitForResult(); @@ -52,8 +49,7 @@ describe(__filename, () => { // transferring funds from the predicate to destination if predicate returns true const tx2 = await predicate.transfer(destinationWallet.address, amountToTransfer, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 100, }); await tx2.waitForResult(); @@ -74,9 +70,8 @@ describe(__filename, () => { }); // transferring funds to the predicate - const tx1 = await wallet.transfer(predicate.address, 300_000, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + const tx1 = await wallet.transfer(predicate.address, 1000, BaseAssetId, { + gasLimit: 100, }); await tx1.waitForResult(); @@ -89,8 +84,7 @@ describe(__filename, () => { // transferring funds from the predicate to destination if predicate returns true const tx2 = await predicate.transfer(destinationWallet.address, amountToTransfer, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 100, }); await tx2.waitForResult(); diff --git a/apps/docs-snippets/src/guide/predicates/send-and-spend-funds-from-predicates.test.ts b/apps/docs-snippets/src/guide/predicates/send-and-spend-funds-from-predicates.test.ts index faaebe065db..aaeefb225a4 100644 --- a/apps/docs-snippets/src/guide/predicates/send-and-spend-funds-from-predicates.test.ts +++ b/apps/docs-snippets/src/guide/predicates/send-and-spend-funds-from-predicates.test.ts @@ -1,3 +1,4 @@ +import { seedTestWallet } from '@fuel-ts/account/test-utils'; import { safeExec } from '@fuel-ts/errors/test-utils'; import type { Provider } from 'fuels'; import { WalletUnlocked, Predicate, BN, getRandomB256, BaseAssetId } from 'fuels'; @@ -14,14 +15,20 @@ import { getTestWallet } from '../../utils'; describe(__filename, () => { let walletWithFunds: WalletUnlocked; let provider: Provider; - let gasPrice: BN; const { abiContents: abi, binHexlified: bin } = getDocsSnippetsForcProject( DocSnippetProjectsEnum.SIMPLE_PREDICATE ); beforeAll(async () => { walletWithFunds = await getTestWallet(); provider = walletWithFunds.provider; - ({ minGasPrice: gasPrice } = provider.getGasConfig()); + const inputAddress = '0xfc05c23a8f7f66222377170ddcbfea9c543dff0dd2d2ba4d0478a4521423a9d4'; + const predicate = new Predicate({ + bytecode: bin, + provider, + abi, + inputData: [inputAddress], + }); + await seedTestWallet(predicate, [[100_000]]); }); it('should successfully use predicate to spend assets', async () => { @@ -36,11 +43,10 @@ describe(__filename, () => { // #endregion send-and-spend-funds-from-predicates-2 // #region send-and-spend-funds-from-predicates-3 - const amountToPredicate = 10_000; - + const amountToPredicate = 1000; + const amountToReceiver = 200; const tx = await walletWithFunds.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, - gasLimit: 1_000, + gasLimit: 100, }); await tx.waitForResult(); @@ -57,11 +63,10 @@ describe(__filename, () => { const tx2 = await predicate.transfer( receiverWallet.address.toB256(), - amountToPredicate - 1000, + amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 1_000, + gasLimit: 100, } ); @@ -77,15 +82,6 @@ describe(__filename, () => { inputData: ['0xfc05c23a8f7f66222377170ddcbfea9c543dff0dd2d2ba4d0478a4521423a9d4'], }); - const amountToPredicate = 100; - - const tx = await walletWithFunds.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, - gasLimit: 1_000, - }); - - await tx.waitForResult(); - const predicateBalance = new BN(await predicate.getBalance()).toNumber(); const receiverWallet = WalletUnlocked.generate({ @@ -93,10 +89,7 @@ describe(__filename, () => { }); const { error } = await safeExec(() => - predicate.transfer(receiverWallet.address, predicateBalance, BaseAssetId, { - gasPrice, - gasLimit: 1_000, - }) + predicate.transfer(receiverWallet.address, predicateBalance, BaseAssetId) ); // #region send-and-spend-funds-from-predicates-6 @@ -117,11 +110,10 @@ describe(__filename, () => { inputData: [getRandomB256()], }); - const amountToPredicate = 10_000; + const amountToPredicate = 10000; const tx = await walletWithFunds.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, - gasLimit: 1_000, + gasLimit: 100, }); await tx.waitForResult(); @@ -130,10 +122,11 @@ describe(__filename, () => { provider, }); + const amountToWallet = 150; + const { error } = await safeExec(() => - predicate.transfer(receiverWallet.address, amountToPredicate, BaseAssetId, { - gasPrice, - gasLimit: 1_000, + predicate.transfer(receiverWallet.address, amountToWallet, BaseAssetId, { + gasLimit: 100, }) ); @@ -153,27 +146,19 @@ describe(__filename, () => { inputData: [inputAddress], }); - const amountToPredicate = 10_000; - - const tx = await walletWithFunds.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, - gasLimit: 1_000, - }); - - await tx.waitForResult(); - const receiverWallet = WalletUnlocked.generate({ provider, }); + const amountToReceiver = 200; + // #region send-and-spend-funds-from-predicates-8 const transactionRequest = await predicate.createTransfer( receiverWallet.address, - amountToPredicate, + amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 1_000, + gasLimit: 100, } ); 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 e780db80673..8c35b7db811 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 @@ -1,5 +1,5 @@ import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils'; -import { BN, ContractFactory, BaseAssetId, ScriptTransactionRequest } from 'fuels'; +import { BN, ContractFactory, BaseAssetId, ScriptTransactionRequest, coinQuantityfy } from 'fuels'; import type { CoinQuantityLike, Contract, WalletUnlocked, Provider } from 'fuels'; import { @@ -34,8 +34,7 @@ describe(__filename, () => { wallet = await getTestWallet(seedQuantities); provider = wallet.provider; const factory = new ContractFactory(contractBin, contractAbi, wallet); - const { minGasPrice: gasPrice } = wallet.provider.getGasConfig(); - contract = await factory.deployContract({ gasPrice }); + contract = await factory.deployContract(); }); it('transfer multiple assets to a contract', async () => { @@ -46,16 +45,13 @@ describe(__filename, () => { expect(contractInitialBalanceAssetB).toStrictEqual(new BN(0)); // #region custom-transactions-2 - // #import { BN, CoinQuantityLike, ScriptTransactionRequest }; + // #import { BN, ScriptTransactionRequest }; // 1. Create a script transaction using the script binary - const { minGasPrice } = contract.provider.getGasConfig(); - const request = new ScriptTransactionRequest({ ...defaultTxParams, gasLimit: 3_000_000, script: scriptBin, - gasPrice: minGasPrice, }); // 2. Instantiate the script main arguments @@ -70,19 +66,16 @@ describe(__filename, () => { // 3. Populate the script data and add the contract input and output request.setData(abiContents, scriptArguments).addContractInputAndOutput(contract.id); - // 4. Calculate the transaction fee - const { maxFee } = await provider.getTransactionCost(request); + // 4. Get the transaction resources + const quantities = [coinQuantityfy([1000, ASSET_A]), coinQuantityfy([500, ASSET_B])]; - // 5. Get the transaction resources - const quantities: CoinQuantityLike[] = [ - [1000, ASSET_A], - [500, ASSET_B], - [maxFee, BaseAssetId], - ]; + // 5. Calculate the transaction fee + const txCost = await provider.getTransactionCost(request, { quantitiesToContract: quantities }); - const resources = await wallet.getResourcesToSpend(quantities); + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - request.addResources(resources); + await wallet.fund(request, txCost); // 6. Send the transaction const tx = await wallet.sendTransaction(request); diff --git a/apps/docs-snippets/src/guide/testing/tweaking-the-blockchain.test.ts b/apps/docs-snippets/src/guide/testing/tweaking-the-blockchain.test.ts index 9f201a65a40..89c07677412 100644 --- a/apps/docs-snippets/src/guide/testing/tweaking-the-blockchain.test.ts +++ b/apps/docs-snippets/src/guide/testing/tweaking-the-blockchain.test.ts @@ -7,7 +7,7 @@ import { Provider, DateTime } from 'fuels'; test('produceBlocks with custom timestamp docs snippet', async () => { // TODO: reevaluate/replace after #1356 const { cleanup, ip, port } = await launchNode({}); - const url = `http://${ip}:${port}/graphql`; + const url = `http://${ip}:${port}/v1/graphql`; const provider = await Provider.create(url); const latestBlock = await provider.getBlock('latest'); if (!latestBlock) { diff --git a/apps/docs-snippets/src/guide/wallets/instantiating-wallets.test.ts b/apps/docs-snippets/src/guide/wallets/instantiating-wallets.test.ts index 1dada348fff..992ab77eca8 100644 --- a/apps/docs-snippets/src/guide/wallets/instantiating-wallets.test.ts +++ b/apps/docs-snippets/src/guide/wallets/instantiating-wallets.test.ts @@ -80,7 +80,8 @@ describe(__filename, () => { expect(myWallet).toBeDefined(); }); - it('should connect a wallet to a provider', async () => { + // TODO: remove skip from testnet test + it.skip('should connect a wallet to a provider', async () => { const address = `0xada436e1b80f855f94d678771c384504e46335f571aa244f11b5a70fe3e61644`; const myWallet = Wallet.fromAddress(address); diff --git a/apps/docs-snippets/src/utils.ts b/apps/docs-snippets/src/utils.ts index 06e69e3bbd7..143429c1a3e 100644 --- a/apps/docs-snippets/src/utils.ts +++ b/apps/docs-snippets/src/utils.ts @@ -23,13 +23,8 @@ export const getTestWallet = async (seedQuantities?: CoinQuantityLike[]) => { // create a new test wallet const testWallet = Wallet.generate({ provider }); - const { minGasPrice } = provider.getGasConfig(); - // create a transaction request to transfer resources to the test wallet - const request = new ScriptTransactionRequest({ - gasLimit: 10000, - gasPrice: minGasPrice, - }); + const request = new ScriptTransactionRequest(); // add the transaction outputs (coins to be sent to the test wallet) (seedQuantities || [[1_000_000, BaseAssetId]]) @@ -37,13 +32,13 @@ export const getTestWallet = async (seedQuantities?: CoinQuantityLike[]) => { .forEach(({ amount, assetId }) => request.addCoinOutput(testWallet.address, amount, assetId)); // get the cost of the transaction - const { minFee, requiredQuantities, gasUsed } = - await genesisWallet.provider.getTransactionCost(request); + const txCost = await genesisWallet.provider.getTransactionCost(request); - request.gasLimit = gasUsed; + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; // funding the transaction with the required quantities - await genesisWallet.fund(request, requiredQuantities, minFee); + await genesisWallet.fund(request, txCost); await genesisWallet.sendTransaction(request, { awaitExecution: true }); @@ -59,15 +54,11 @@ export const createAndDeployContractFromProject = async ( const contractFactory = new ContractFactory(binHexlified, abiContents, wallet); - const { minGasPrice } = wallet.provider.getGasConfig(); - return contractFactory.deployContract({ storageSlots, - gasPrice: minGasPrice, }); }; export const defaultTxParams = { gasLimit: 10000, - gasPrice: 1, }; diff --git a/packages/abi-coder/src/utils/constants.ts b/packages/abi-coder/src/utils/constants.ts index bc5f05bc6ee..5f67ba62adb 100644 --- a/packages/abi-coder/src/utils/constants.ts +++ b/packages/abi-coder/src/utils/constants.ts @@ -69,7 +69,6 @@ export const INPUT_COIN_FIXED_SIZE = ASSET_ID_LEN + // Asset id TX_POINTER_LEN + // TxPointer WORD_SIZE + // Witnesses index - WORD_SIZE + // Maturity WORD_SIZE + // Predicate size WORD_SIZE + // Predicate data size WORD_SIZE; // Predicate gas used diff --git a/packages/abi-typegen/src/templates/contract/bytecode.test.ts b/packages/abi-typegen/src/templates/contract/bytecode.test.ts index e110dfb93a7..e6fbcfc2bd5 100644 --- a/packages/abi-typegen/src/templates/contract/bytecode.test.ts +++ b/packages/abi-typegen/src/templates/contract/bytecode.test.ts @@ -25,6 +25,6 @@ describe('templates/contract/bytecode', () => { // validating restore(); - expect(rendered.trim()).toEqual(bytecodeTemplate); + expect(rendered.trim()).toEqual(bytecodeTemplate.trim()); }); }); diff --git a/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs b/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs index 0693e86bdf1..33096db6af7 100644 --- a/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs +++ b/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs @@ -9,4 +9,4 @@ Fuel-Core version: 33.33.33 */ -export default '0x740000034700000000000000000000445dfcc00110fff3005d4060495d47f001134904407648000272f0007b36f000001aec5000910000005c43f000244000004700000001000000000000000000000055b7ae10' \ No newline at end of file +export default '0x740000034700000000000000000000445dfcc00110fff3005d4060495d47f001134904407648000272f0007b36f000001aec50005c43f00024400000470000000000000001000000000000000000000055b7ae10' diff --git a/packages/account/README.md b/packages/account/README.md index 5a6d69f99e4..0a9540892fa 100644 --- a/packages/account/README.md +++ b/packages/account/README.md @@ -47,7 +47,7 @@ import { bn } from "@fuel-ts/math"; import { BaseAssetId } from "fuels"; import { seedTestWallet, generateTestWallet } from "@account/test-utils"; -const provider = await Provider.create("http://127.0.0.1:4000/graphql"); +const provider = await Provider.create("http://127.0.0.1:4000/v1/graphql"); // seeding const wallet = Wallet.fromPrivateKey("0x...", provider); diff --git a/packages/account/package.json b/packages/account/package.json index 3e934dcb67d..2607f32d915 100644 --- a/packages/account/package.json +++ b/packages/account/package.json @@ -42,7 +42,7 @@ "scripts": { "build": "tsup", "prebuild": "pnpm build:operations", - "build:schema": "get-graphql-schema http://localhost:4000/graphql > src/providers/fuel-core-schema.graphql && prettier --write src/providers/fuel-core-schema.graphql", + "build:schema": "get-graphql-schema http://localhost:4000/v1/graphql > src/providers/fuel-core-schema.graphql && prettier --write src/providers/fuel-core-schema.graphql", "build:operations": "pnpm graphql-codegen", "postbuild": "tsx ../../scripts/postbuild.ts" }, diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index 040bfb58d34..c35dfd66e0b 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -2,7 +2,6 @@ import { Address } from '@fuel-ts/address'; import { BaseAssetId } from '@fuel-ts/address/configs'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import type { BN } from '@fuel-ts/math'; import { bn } from '@fuel-ts/math'; import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils'; @@ -15,7 +14,6 @@ import { generateTestWallet, seedTestWallet } from './test-utils'; import { Wallet } from './wallet'; let provider: Provider; -let gasPrice: BN; afterEach(() => { vi.restoreAllMocks(); @@ -23,7 +21,6 @@ afterEach(() => { beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); }); /** @@ -260,17 +257,22 @@ describe('Account', () => { const addResourcesSpy = vi.spyOn(request, 'addResources'); - const addAmountToAssetSpy = vi.spyOn(providersMod, 'addAmountToAsset'); + const addAmountToCoinQuantitiesSpy = vi.spyOn(providersMod, 'addAmountToCoinQuantities'); const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', provider ); - await account.fund(request, quantities, fee); + await account.fund(request, { + requiredQuantities: quantities, + maxFee: fee, + estimatedPredicates: [], + addedSignatures: 0, + }); - expect(addAmountToAssetSpy).toBeCalledTimes(1); - expect(addAmountToAssetSpy).toHaveBeenCalledWith({ + expect(addAmountToCoinQuantitiesSpy).toBeCalledTimes(1); + expect(addAmountToCoinQuantitiesSpy).toHaveBeenCalledWith({ amount: bn(fee), assetId: BaseAssetId, coinQuantities: quantities, @@ -374,7 +376,6 @@ describe('Account', () => { const receiver = await generateTestWallet(provider); const response = await sender.transfer(receiver.address, 1, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await response.wait(); @@ -391,7 +392,6 @@ describe('Account', () => { const receiver = await generateTestWallet(provider); const request = await sender.createTransfer(receiver.address.toB256(), 1, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); @@ -411,7 +411,6 @@ describe('Account', () => { const response = await sender.transfer(receiver.address, 1, BaseAssetId, { gasLimit: 600, - gasPrice, }); await response.wait(); @@ -441,7 +440,7 @@ describe('Account', () => { const assetIdB = ASSET_B; const amount = 1; - const request = new ScriptTransactionRequest({ gasLimit: 1000000, gasPrice }); + const request = new ScriptTransactionRequest({ gasLimit: 1000000 }); const sender = await generateTestWallet(provider, [ [500_000, assetIdA], [500_000, assetIdB], @@ -450,13 +449,6 @@ describe('Account', () => { const receiverA = await generateTestWallet(provider); const receiverB = await generateTestWallet(provider); - const resources = await sender.getResourcesToSpend([ - [500_000, BaseAssetId], - [500_000, assetIdA], - [500_000, assetIdB], - ]); - - request.addResources(resources); request.addCoinOutputs(receiverA.address, [ [amount, assetIdA], [amount, assetIdB], @@ -466,6 +458,13 @@ describe('Account', () => { [amount, assetIdB], ]); + const txCost = await sender.provider.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await sender.fund(request, txCost); + const response = await sender.sendTransaction(request); await response.wait(); @@ -494,7 +493,7 @@ describe('Account', () => { ); const amount = 10; - const tx = await sender.withdrawToBaseLayer(recipient, 10, { gasPrice, gasLimit: 10_000 }); + const tx = await sender.withdrawToBaseLayer(recipient, 10, { gasLimit: 10_000 }); const result = await tx.waitForResult(); const messageOutReceipt = result.receipts[0]; @@ -522,7 +521,6 @@ describe('Account', () => { // Wait for the next block to be minter on out case we are using a local provider // so we can create a new tx to generate next block const resp = await sender.transfer(recipient, AMOUNT, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); const nextBlock = await resp.waitForResult(); @@ -553,7 +551,6 @@ describe('Account', () => { await seedTestWallet(sender, [[500_000, BaseAssetId]]); const transfer = await sender.transfer(receiver.address, 110, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await transfer.wait(); @@ -574,7 +571,9 @@ describe('Account', () => { '0x00000000000000000000000047ba61eec8e5e65247d717ff236f504cf3b0a263' ); const amount = 110; - const tx = await sender.withdrawToBaseLayer(recipient, amount, { gasPrice, gasLimit: 10_000 }); + const tx = await sender.withdrawToBaseLayer(recipient, amount, { + gasLimit: 10_000, + }); const result = await tx.wait(); const messageOutReceipt = result.receipts[0]; @@ -587,22 +586,15 @@ describe('Account', () => { }); it('should ensure gas price and gas limit are validated when transfering amounts', async () => { - const sender = await generateTestWallet(provider); + const sender = await generateTestWallet(provider, [[1000, BaseAssetId]]); const receiver = Wallet.generate({ provider }); await expect(async () => { const result = await sender.transfer(receiver.address, 1, BaseAssetId, { - gasLimit: 0, - }); - await result.wait(); - }).rejects.toThrowError(/Gas limit '0' is lower than the required: ./); - - await expect(async () => { - const result = await sender.transfer(receiver.address, 1, BaseAssetId, { - gasPrice: 0, + gasLimit: 1, }); await result.wait(); - }).rejects.toThrowError(/Gas price '0' is lower than the required: ./); + }).rejects.toThrowError(/Gas limit '1' is lower than the required: ./); }); it('should ensure gas limit and price are validated when withdraw an amount of base asset', async () => { @@ -613,17 +605,10 @@ describe('Account', () => { await expect(async () => { const result = await sender.withdrawToBaseLayer(recipient, 10, { - gasPrice: 0, - }); - await result.wait(); - }).rejects.toThrowError(/Gas price '0' is lower than the required: ./); - - await expect(async () => { - const result = await sender.withdrawToBaseLayer(recipient, 10, { - gasLimit: 0, + gasLimit: 1, }); await result.wait(); - }).rejects.toThrowError(/Gas limit '0' is lower than the required: ./); + }).rejects.toThrowError(/Gas limit '1' is lower than the required: ./); }); it('should throw when trying to transfer a zero or negative amount', async () => { diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index edda171c2d9..a8da4a80e97 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -6,6 +6,7 @@ import type { AbstractAddress, BytesLike } from '@fuel-ts/interfaces'; import type { BigNumberish, BN } from '@fuel-ts/math'; import { bn } from '@fuel-ts/math'; import { arrayify } from '@fuel-ts/utils'; +import { clone } from 'ramda'; import type { FuelConnector } from './connectors'; import type { @@ -23,18 +24,25 @@ import type { ProviderSendTxParams, TransactionResponse, EstimateTransactionParams, + TransactionCost, } from './providers'; import { withdrawScript, ScriptTransactionRequest, transactionRequestify, - addAmountToAsset, + addAmountToCoinQuantities, + cacheTxInputsFromOwner, } from './providers'; import { assembleTransferToContractScript } from './utils/formatTransferToContractScriptData'; export type TxParamsType = Pick< ScriptTransactionRequestLike, - 'gasLimit' | 'gasPrice' | 'maturity' | 'maxFee' | 'witnessLimit' + 'gasLimit' | 'tip' | 'maturity' | 'maxFee' | 'witnessLimit' +>; + +export type EstimatedTxParams = Pick< + TransactionCost, + 'maxFee' | 'estimatedPredicates' | 'addedSignatures' | 'requiredQuantities' >; /** @@ -237,32 +245,26 @@ export class Account extends AbstractAccount { * @param fee - The estimated transaction fee. * @returns A promise that resolves when the resources are added to the transaction. */ - async fund( - request: T, - coinQuantities: CoinQuantity[], - fee: BN - ): Promise { - const updatedQuantities = addAmountToAsset({ + async fund(request: T, params: EstimatedTxParams): Promise { + const { addedSignatures, estimatedPredicates, maxFee: fee, requiredQuantities } = params; + + const txRequest = request as T; + const requiredQuantitiesWithFee = addAmountToCoinQuantities({ amount: bn(fee), assetId: BaseAssetId, - coinQuantities, + coinQuantities: requiredQuantities, }); const quantitiesDict: Record = {}; - updatedQuantities.forEach(({ amount, assetId }) => { + requiredQuantitiesWithFee.forEach(({ amount, assetId }) => { quantitiesDict[assetId] = { required: amount, owned: bn(0), }; }); - const cachedUtxos: BytesLike[] = []; - const cachedMessages: BytesLike[] = []; - - const owner = this.address.toB256(); - - request.inputs.forEach((input) => { + txRequest.inputs.forEach((input) => { const isResource = 'amount' in input; if (isResource) { @@ -270,18 +272,12 @@ export class Account extends AbstractAccount { if (isCoin) { const assetId = String(input.assetId); - if (input.owner === owner && quantitiesDict[assetId]) { + if (quantitiesDict[assetId]) { const amount = bn(input.amount); quantitiesDict[assetId].owned = quantitiesDict[assetId].owned.add(amount); - - // caching this utxo to avoid fetching it again if requests needs to be funded - cachedUtxos.push(input.id); } - } else if (input.recipient === owner && input.amount && quantitiesDict[BaseAssetId]) { + } else if (input.amount && quantitiesDict[BaseAssetId]) { quantitiesDict[BaseAssetId].owned = quantitiesDict[BaseAssetId].owned.add(input.amount); - - // caching this message to avoid fetching it again if requests needs to be funded - cachedMessages.push(input.nonce); } } }); @@ -299,12 +295,30 @@ export class Account extends AbstractAccount { const needsToBeFunded = missingQuantities.length; if (needsToBeFunded) { - const resources = await this.getResourcesToSpend(missingQuantities, { - messages: cachedMessages, - utxos: cachedUtxos, - }); - request.addResources(resources); + const excludedIds = cacheTxInputsFromOwner(txRequest.inputs, this.address.toString()); + + const resources = await this.getResourcesToSpend(missingQuantities, excludedIds); + + txRequest.addResources(resources); } + + txRequest.shiftPredicateData(); + txRequest.updatePredicateGasUsed(estimatedPredicates); + + const requestToBeReEstimate = clone(txRequest); + if (addedSignatures) { + Array.from({ length: addedSignatures }).forEach(() => + requestToBeReEstimate.addEmptyWitness() + ); + } + + const { maxFee } = await this.provider.estimateTxGasAndFee({ + transactionRequest: requestToBeReEstimate, + }); + + txRequest.maxFee = maxFee; + + return txRequest; } /** @@ -313,7 +327,7 @@ export class Account extends AbstractAccount { * @param destination - The address of the destination. * @param amount - The amount of coins to transfer. * @param assetId - The asset ID of the coins to transfer. - * @param txParams - The transaction parameters (gasLimit, gasPrice, maturity). + * @param txParams - The transaction parameters (gasLimit, tip, maturity, maxFee, witnessLimit). * @returns A promise that resolves to the prepared transaction request. */ async createTransfer( @@ -326,29 +340,26 @@ export class Account extends AbstractAccount { /** Tx Params */ txParams: TxParamsType = {} ): Promise { - const { minGasPrice } = this.provider.getGasConfig(); - const params = { gasPrice: minGasPrice, ...txParams }; - const request = new ScriptTransactionRequest(params); + const request = new ScriptTransactionRequest(txParams); request.addCoinOutput(Address.fromAddressOrString(destination), amount, assetId); - const { maxFee, requiredQuantities, gasUsed, estimatedInputs } = - await this.provider.getTransactionCost(request, [], { - estimateTxDependencies: true, - resourcesOwner: this, - }); - - request.gasPrice = bn(txParams.gasPrice ?? minGasPrice); - request.gasLimit = bn(txParams.gasLimit ?? gasUsed); - - this.validateGas({ - gasUsed, - gasPrice: request.gasPrice, - gasLimit: request.gasLimit, - minGasPrice, + const txCost = await this.provider.getTransactionCost(request, { + estimateTxDependencies: true, + resourcesOwner: this, }); - await this.fund(request, requiredQuantities, maxFee); + // TODO: Fix this logic. The if was not working when gasLimit was 0, "if(txParams.gasLimit)" + // was being evaluated as false. Should we change this on master? + if ('gasLimit' in txParams) { + this.validateGas({ + gasUsed: txCost.gasUsed, + gasLimit: request.gasLimit, + }); + } + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - request.updatePredicateInputs(estimatedInputs); + await this.fund(request, txCost); return request; } @@ -409,8 +420,6 @@ export class Account extends AbstractAccount { } const contractAddress = Address.fromAddressOrString(contractId); - const { minGasPrice } = this.provider.getGasConfig(); - const params = { gasPrice: minGasPrice, ...txParams }; const { script, scriptData } = await assembleTransferToContractScript({ hexlifiedContractId: contractAddress.toB256(), @@ -419,28 +428,28 @@ export class Account extends AbstractAccount { }); const request = new ScriptTransactionRequest({ - ...params, + ...txParams, script, scriptData, }); request.addContractInputAndOutput(contractAddress); - const { maxFee, requiredQuantities, gasUsed } = await this.provider.getTransactionCost( - request, - [{ amount: bn(amount), assetId: String(assetId) }] - ); - - request.gasLimit = bn(params.gasLimit ?? gasUsed); - - this.validateGas({ - gasUsed, - gasPrice: request.gasPrice, - gasLimit: request.gasLimit, - minGasPrice, + const txCost = await this.provider.getTransactionCost(request, { + resourcesOwner: this, + quantitiesToContract: [{ amount: bn(amount), assetId: String(assetId) }], }); + if (txParams.gasLimit) { + this.validateGas({ + gasUsed: txCost.gasUsed, + gasLimit: request.gasLimit, + }); + } - await this.fund(request, requiredQuantities, maxFee); + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await this.fund(request, txCost); return this.sendTransaction(request); } @@ -461,8 +470,6 @@ export class Account extends AbstractAccount { /** Tx Params */ txParams: TxParamsType = {} ): Promise { - const { minGasPrice } = this.provider.getGasConfig(); - const recipientAddress = Address.fromAddressOrString(recipient); // add recipient and amount to the transaction script code const recipientDataArray = arrayify( @@ -477,26 +484,24 @@ export class Account extends AbstractAccount { ...amountDataArray, ]); - const params: ScriptTransactionRequestLike = { script, gasPrice: minGasPrice, ...txParams }; + const params: ScriptTransactionRequestLike = { script, ...txParams }; const request = new ScriptTransactionRequest(params); - const forwardingQuantities = [{ amount: bn(amount), assetId: BaseAssetId }]; + const quantitiesToContract = [{ amount: bn(amount), assetId: BaseAssetId }]; - const { requiredQuantities, maxFee, gasUsed } = await this.provider.getTransactionCost( - request, - forwardingQuantities - ); + const txCost = await this.provider.getTransactionCost(request, { quantitiesToContract }); - request.gasLimit = bn(params.gasLimit ?? gasUsed); + if (txParams.gasLimit) { + this.validateGas({ + gasUsed: txCost.gasUsed, + gasLimit: request.gasLimit, + }); + } - this.validateGas({ - gasUsed, - gasPrice: request.gasPrice, - gasLimit: request.gasLimit, - minGasPrice, - }); + request.maxFee = txCost.maxFee; + request.gasLimit = txCost.gasUsed; - await this.fund(request, requiredQuantities, maxFee); + await this.fund(request, txCost); return this.sendTransaction(request); } @@ -566,24 +571,7 @@ export class Account extends AbstractAccount { return this.provider.simulate(transactionRequest, { estimateTxDependencies: false }); } - private validateGas({ - gasUsed, - gasPrice, - gasLimit, - minGasPrice, - }: { - gasUsed: BN; - gasPrice: BN; - gasLimit: BN; - minGasPrice: BN; - }) { - if (minGasPrice.gt(gasPrice)) { - throw new FuelError( - ErrorCode.GAS_PRICE_TOO_LOW, - `Gas price '${gasPrice}' is lower than the required: '${minGasPrice}'.` - ); - } - + private validateGas({ gasUsed, gasLimit }: { gasUsed: BN; gasLimit: BN }) { if (gasUsed.gt(gasLimit)) { throw new FuelError( ErrorCode.GAS_LIMIT_TOO_LOW, diff --git a/packages/account/src/configs.test.ts b/packages/account/src/configs.test.ts index 9aa1e5272fb..c3284dd3774 100644 --- a/packages/account/src/configs.test.ts +++ b/packages/account/src/configs.test.ts @@ -4,7 +4,7 @@ describe('Configs', () => { it('exports FUEL_NETWORK_URL', async () => { const configs = await import('./configs'); - expect(configs.FUEL_NETWORK_URL).toBe('http://127.0.0.1:4000/graphql'); + expect(configs.FUEL_NETWORK_URL).toBe('http://127.0.0.1:4000/v1/graphql'); }); it('exports FUEL_BETA_5_NETWORK_URL', async () => { @@ -35,7 +35,7 @@ describe('Configs - undefined process', () => { const configs = await import('./configs'); - expect(configs.FUEL_NETWORK_URL).toBe('http://127.0.0.1:4000/graphql'); + expect(configs.FUEL_NETWORK_URL).toBe('http://127.0.0.1:4000/v1/graphql'); }); }); diff --git a/packages/account/src/configs.ts b/packages/account/src/configs.ts index 1b20f664b26..a27666b15b7 100644 --- a/packages/account/src/configs.ts +++ b/packages/account/src/configs.ts @@ -1,6 +1,6 @@ export const FUEL_NETWORK_URL: string = typeof process !== 'undefined' - ? process?.env?.FUEL_NETWORK_URL || 'http://127.0.0.1:4000/graphql' - : 'http://127.0.0.1:4000/graphql'; + ? process?.env?.FUEL_NETWORK_URL || 'http://127.0.0.1:4000/v1/graphql' + : 'http://127.0.0.1:4000/v1/graphql'; export const FUEL_BETA_5_NETWORK_URL: string = 'https://beta-5.fuel.network/graphql'; diff --git a/packages/account/src/predicate/predicate.ts b/packages/account/src/predicate/predicate.ts index 824ce96b569..3a2d5c8bc95 100644 --- a/packages/account/src/predicate/predicate.ts +++ b/packages/account/src/predicate/predicate.ts @@ -19,8 +19,10 @@ import type { TxParamsType } from '../account'; import { transactionRequestify, BaseTransactionRequest } from '../providers'; import type { CallResult, + CoinQuantityLike, + ExcludeResourcesOption, Provider, - ProviderSendTxParams, + Resource, TransactionRequest, TransactionRequestLike, TransactionResponse, @@ -73,6 +75,7 @@ export class Predicate extends Account { this.interface = predicateInterface; if (inputData !== undefined && inputData.length > 0) { this.predicateData = inputData; + this.predicateDataBytes = this.getPredicateData(0); } } @@ -90,9 +93,9 @@ export class Predicate extends Account { request.inputs?.forEach((input) => { if (input.type === InputType.Coin && hexlify(input.owner) === this.address.toB256()) { // eslint-disable-next-line no-param-reassign - input.predicate = this.bytes; + input.predicate = hexlify(this.bytes); // eslint-disable-next-line no-param-reassign - input.predicateData = this.getPredicateData(policies.length); + input.predicateData = hexlify(this.getPredicateData(policies.length)); } }); @@ -118,8 +121,7 @@ export class Predicate extends Account { /** Tx Params */ txParams: TxParamsType = {} ): Promise { - const request = await super.createTransfer(destination, amount, assetId, txParams); - return this.populateTransactionPredicateData(request); + return super.createTransfer(destination, amount, assetId, txParams); } /** @@ -128,12 +130,9 @@ export class Predicate extends Account { * @param transactionRequestLike - The transaction request-like object. * @returns A promise that resolves to the transaction response. */ - sendTransaction( - transactionRequestLike: TransactionRequestLike, - options?: Pick - ): Promise { - const transactionRequest = this.populateTransactionPredicateData(transactionRequestLike); - return super.sendTransaction(transactionRequest, options); + sendTransaction(transactionRequestLike: TransactionRequestLike): Promise { + const transactionRequest = transactionRequestify(transactionRequestLike); + return super.sendTransaction(transactionRequest, { estimateTxDependencies: false }); } /** @@ -143,8 +142,8 @@ export class Predicate extends Account { * @returns A promise that resolves to the call result. */ simulateTransaction(transactionRequestLike: TransactionRequestLike): Promise { - const transactionRequest = this.populateTransactionPredicateData(transactionRequestLike); - return super.simulateTransaction(transactionRequest); + const transactionRequest = transactionRequestify(transactionRequestLike); + return super.simulateTransaction(transactionRequest, { estimateTxDependencies: false }); } private getPredicateData(policiesLength: number): Uint8Array { @@ -209,6 +208,30 @@ export class Predicate extends Account { }; } + /** + * Retrieves resources satisfying the spend query for the account. + * + * @param quantities - IDs of coins to exclude. + * @param excludedIds - IDs of resources to be excluded from the query. + * @returns A promise that resolves to an array of Resources. + */ + async getResourcesToSpend( + quantities: CoinQuantityLike[] /** IDs of coins to exclude */, + excludedIds?: ExcludeResourcesOption + ): Promise { + const resources = await this.provider.getResourcesToSpend( + this.address, + quantities, + excludedIds + ); + return resources.map((resource) => ({ + ...resource, + predicate: hexlify(this.bytes), + predicateData: hexlify(this.predicateDataBytes), + paddPredicateData: (policiesLength: number) => hexlify(this.getPredicateData(policiesLength)), + })); + } + /** * Sets the configurable constants for the predicate. * diff --git a/packages/account/src/providers/coin-quantity.ts b/packages/account/src/providers/coin-quantity.ts index f9579bfc442..9f7c3dc2249 100644 --- a/packages/account/src/providers/coin-quantity.ts +++ b/packages/account/src/providers/coin-quantity.ts @@ -38,7 +38,7 @@ export interface IAddAmountToAssetParams { coinQuantities: CoinQuantity[]; } -export const addAmountToAsset = (params: IAddAmountToAssetParams): CoinQuantity[] => { +export const addAmountToCoinQuantities = (params: IAddAmountToAssetParams): CoinQuantity[] => { const { amount, assetId } = params; const coinQuantities = [...params.coinQuantities]; diff --git a/packages/account/src/providers/coin.ts b/packages/account/src/providers/coin.ts index b1c80ba1be4..6da626f5120 100644 --- a/packages/account/src/providers/coin.ts +++ b/packages/account/src/providers/coin.ts @@ -1,4 +1,4 @@ -import type { AbstractAddress } from '@fuel-ts/interfaces'; +import type { AbstractAddress, BytesLike } from '@fuel-ts/interfaces'; import type { BN } from '@fuel-ts/math'; /** @@ -9,7 +9,9 @@ export type Coin = { assetId: string; amount: BN; owner: AbstractAddress; - maturity: number; blockCreated: BN; txCreatedIdx: BN; + predicate?: BytesLike; + predicateData?: BytesLike; + paddPredicateData?: (policiesLenght: number) => BytesLike; }; diff --git a/packages/account/src/providers/fuel-core-schema.graphql b/packages/account/src/providers/fuel-core-schema.graphql index 25983ae2625..18d87b27c9c 100644 --- a/packages/account/src/providers/fuel-core-schema.graphql +++ b/packages/account/src/providers/fuel-core-schema.graphql @@ -49,6 +49,7 @@ input BalanceFilterInput { type Block { id: BlockId! + height: U32! header: Header! consensus: Consensus! transactions: [Transaction!]! @@ -88,6 +89,9 @@ type BlockEdge { scalar BlockId +""" +Breakpoint, defined as a tuple of contract ID and relative PC offset inside it +""" input Breakpoint { contract: ContractId! pc: U64! @@ -114,7 +118,6 @@ type Coin { owner: Address! amount: U64! assetId: AssetId! - maturity: U32! """ TxPointer - the height of the block this coin was created in @@ -247,7 +250,7 @@ input ContractBalanceFilterInput { } type ContractCreated { - contract: Contract! + contract: ContractId! stateRoot: Bytes32! } @@ -266,6 +269,29 @@ type ContractParameters { union DependentCost = LightOperation | HeavyOperation +type DryRunFailureStatus { + programState: ProgramState + reason: String! + receipts: [Receipt!]! +} + +type DryRunSuccessStatus { + programState: ProgramState + receipts: [Receipt!]! +} + +type DryRunTransactionExecutionStatus { + id: TransactionId! + status: DryRunTransactionStatus! + receipts: [Receipt!]! +} + +union DryRunTransactionStatus = DryRunSuccessStatus | DryRunFailureStatus + +type EstimateGasPrice { + gasPrice: U64! +} + input ExcludeInput { """ Utxos to exclude from the selection. @@ -305,7 +331,6 @@ type GasCosts { cb: U64! cfei: U64! cfsi: U64! - croo: U64! div: U64! divi: U64! ecr1: U64! @@ -384,6 +409,7 @@ type GasCosts { xori: U64! call: DependentCost! ccp: DependentCost! + croo: DependentCost! csiz: DependentCost! k256: DependentCost! ldc: DependentCost! @@ -496,7 +522,6 @@ type InputCoin { assetId: AssetId! txPointer: TxPointer! witnessIndex: Int! - maturity: U32! predicateGasUsed: U64! predicate: HexString! predicateData: HexString! @@ -507,7 +532,7 @@ type InputContract { balanceRoot: Bytes32! stateRoot: Bytes32! txPointer: TxPointer! - contract: Contract! + contractId: ContractId! } type InputMessage { @@ -522,6 +547,11 @@ type InputMessage { predicateData: HexString! } +type LatestGasPrice { + gasPrice: U64! + blockHeight: U32! +} + type LightOperation { base: U64! unitsPerGas: U64! @@ -605,19 +635,58 @@ type MessageStatus { } type Mutation { + """ + Initialize a new debugger session, returning its ID. + A new VM instance is spawned for each session. + The session is run in a separate database transaction, + on top of the most recent node state. + """ startSession: ID! + + """ + End debugger session. + """ endSession(id: ID!): Boolean! + + """ + Reset the VM instance to the initial state. + """ reset(id: ID!): Boolean! + + """ + Execute a single fuel-asm instruction. + """ execute(id: ID!, op: String!): Boolean! + + """ + Set single-stepping mode for the VM instance. + """ setSingleStepping(id: ID!, enable: Boolean!): Boolean! + + """ + Set a breakpoint for a VM instance. + """ setBreakpoint(id: ID!, breakpoint: Breakpoint!): Boolean! + + """ + Run a single transaction in given session until it + hits a breakpoint or completes. + """ startTx(id: ID!, txJson: String!): RunResult! + + """ + Resume execution of the VM instance after a breakpoint. + Runs until the next breakpoint or until the transaction completes. + """ continueTx(id: ID!): RunResult! """ - Execute a dry-run of the transaction using a fork of current state, no changes are committed. + Execute a dry-run of multiple transactions using a fork of current state, no changes are committed. """ - dryRun(tx: HexString!, utxoValidation: Boolean): [Receipt!]! + dryRun( + txs: [HexString!]! + utxoValidation: Boolean + ): [DryRunTransactionExecutionStatus!]! """ Submits transaction to the `TxPool`. @@ -728,7 +797,7 @@ type PoAConsensus { } type Policies { - gasPrice: U64 + tip: U64 witnessLimit: U64 maturity: U32 maxFee: U64 @@ -747,7 +816,14 @@ type ProgramState { } type Query { + """ + Read register value by index. + """ register(id: ID!, register: U32!): U64! + + """ + Read read a range of memory bytes. + """ memory(id: ID!, start: U32!, size: U32!): String! balance( """ @@ -876,6 +952,19 @@ type Query { before: String ): ContractBalanceConnection! nodeInfo: NodeInfo! + latestGasPrice: LatestGasPrice! + estimateGasPrice( + """ + Number of blocks into the future to estimate the gas price for + """ + blockHorizon: U32 + ): EstimateGasPrice! + message( + """ + The Nonce of the message + """ + nonce: Nonce! + ): Message messages( """ address of the owner @@ -896,10 +985,10 @@ type Query { } type Receipt { - contract: Contract + id: ContractId pc: U64 is: U64 - to: Contract + to: ContractId toAddress: Address amount: U64 assetId: AssetId @@ -922,6 +1011,10 @@ type Receipt { sender: Address recipient: Address nonce: Nonce + + """ + Set in the case of a Panic receipt to indicate a missing contract input id + """ contractId: ContractId subId: Bytes32 } @@ -1041,14 +1134,14 @@ scalar Tai64Timestamp type Transaction { id: TransactionId! inputAssetIds: [AssetId!] - inputContracts: [Contract!] + inputContracts: [ContractId!] inputContract: InputContract policies: Policies - gasPrice: U64 scriptGasLimit: U64 maturity: U32 mintAmount: U64 mintAssetId: AssetId + mintGasPrice: U64 txPointer: TxPointer isScript: Boolean! isCreate: Boolean! @@ -1059,7 +1152,6 @@ type Transaction { witnesses: [HexString!] receiptsRoot: Bytes32 status: TransactionStatus - receipts: [Receipt!] script: HexString scriptData: HexString bytecodeWitnessIndex: Int diff --git a/packages/account/src/providers/fuel-graphql-subscriber.ts b/packages/account/src/providers/fuel-graphql-subscriber.ts index acabd3b6c5a..a9144fea9b2 100644 --- a/packages/account/src/providers/fuel-graphql-subscriber.ts +++ b/packages/account/src/providers/fuel-graphql-subscriber.ts @@ -47,7 +47,6 @@ export class FuelGraphqlSubscriber implements AsyncIterator { } const text = FuelGraphqlSubscriber.textDecoder.decode(value); - /** * We don't care about responses that don't start with 'data:' like keep-alive messages. * The only responses that I came across from the node are either 200 responses with data or keep-alive messages. diff --git a/packages/account/src/providers/message.ts b/packages/account/src/providers/message.ts index 35cafa14e16..9da659ec84f 100644 --- a/packages/account/src/providers/message.ts +++ b/packages/account/src/providers/message.ts @@ -25,6 +25,9 @@ export type MessageCoin = { nonce: BytesLike; amount: BN; daHeight: BN; + predicate?: BytesLike; + predicateData?: BytesLike; + paddPredicateData?: (policiesLenght: number) => BytesLike; }; export type MerkleProof = { diff --git a/packages/account/src/providers/operations.graphql b/packages/account/src/providers/operations.graphql index fd1cd2becea..7421341df0e 100644 --- a/packages/account/src/providers/operations.graphql +++ b/packages/account/src/providers/operations.graphql @@ -15,10 +15,16 @@ fragment transactionStatusFragment on TransactionStatus { id } time + receipts { + ...receiptFragment + } programState { returnType data } + receipts { + ...receiptFragment + } } ... on FailureStatus { block { @@ -26,6 +32,9 @@ fragment transactionStatusFragment on TransactionStatus { } time reason + receipts { + ...receiptFragment + } } ... on SqueezedOutStatus { reason @@ -35,10 +44,6 @@ fragment transactionStatusFragment on TransactionStatus { fragment transactionFragment on Transaction { id rawPayload - gasPrice - receipts { - ...receiptFragment - } status { ...transactionStatusFragment } @@ -59,31 +64,26 @@ fragment transactionEstimatePredicatesFragment on Transaction { } } -fragment receiptFragment on Receipt { - contract { - id - # - # NOTE: - # Props removed due to excessive bandwidth usage: - # https://github.com/FuelLabs/fuels-ts/issues/1706 - # - # bytecode - # salt - # +fragment dryRunFailureStatusFragment on DryRunFailureStatus { + reason + programState { + returnType + data } +} + +fragment dryRunSuccessStatusFragment on DryRunSuccessStatus { + programState { + returnType + data + } +} + +fragment receiptFragment on Receipt { + id pc is - to { - id - # - # NOTE: - # Props removed due to excessive bandwidth usage: - # https://github.com/FuelLabs/fuels-ts/issues/1706 - # - # bytecode - # salt - # - } + to toAddress amount assetId @@ -110,10 +110,29 @@ fragment receiptFragment on Receipt { subId } +fragment dryRunTransactionStatusFragment on DryRunTransactionStatus { + ... on DryRunFailureStatus { + ...dryRunFailureStatusFragment + } + ... on DryRunSuccessStatus { + ...dryRunSuccessStatusFragment + } +} + +fragment dryRunTransactionExecutionStatusFragment on DryRunTransactionExecutionStatus { + id + status { + ...dryRunTransactionStatusFragment + } + receipts { + ...receiptFragment + } +} + fragment blockFragment on Block { id + height header { - height time } transactions { @@ -127,7 +146,6 @@ fragment coinFragment on Coin { owner amount assetId - maturity blockCreated txCreatedIdx } @@ -252,7 +270,6 @@ fragment GasCostsFragment on GasCosts { cb cfei cfsi - croo div divi ecr1 @@ -335,6 +352,9 @@ fragment GasCostsFragment on GasCosts { ccp { ...DependentCostFragment } + croo { + ...DependentCostFragment + } csiz { ...DependentCostFragment } @@ -453,14 +473,6 @@ fragment nodeInfoFragment on NodeInfo { maxTx maxDepth nodeVersion - peers { - id - addresses - clientVersion - blockHeight - lastHeartbeatMs - appScore - } } query getNodeInfo { @@ -484,9 +496,6 @@ query getTransaction($transactionId: TransactionId!) { query getTransactionWithReceipts($transactionId: TransactionId!) { transaction(id: $transactionId) { ...transactionFragment - receipts { - ...receiptFragment - } } } @@ -623,6 +632,18 @@ query getBalance($owner: Address!, $assetId: AssetId!) { } } +query getLatestGasPrice { + latestGasPrice { + gasPrice + } +} + +query estimateGasPrice($blockHorizon: U32!) { + estimateGasPrice(blockHorizon: $blockHorizon) { + gasPrice + } +} + query getBalances( $filter: BalanceFilterInput! $after: String @@ -689,9 +710,9 @@ query getMessageStatus($nonce: Nonce!) { } } -mutation dryRun($encodedTransaction: HexString!, $utxoValidation: Boolean) { - dryRun(tx: $encodedTransaction, utxoValidation: $utxoValidation) { - ...receiptFragment +mutation dryRun($encodedTransactions: [HexString!]!, $utxoValidation: Boolean) { + dryRun(txs: $encodedTransactions, utxoValidation: $utxoValidation) { + ...dryRunTransactionExecutionStatusFragment } } diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index ebb0d5c92ab..1a1221b1a66 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -51,7 +51,7 @@ const getCustomFetch = }; // TODO: Figure out a way to import this constant from `@fuel-ts/account/configs` -const FUEL_NETWORK_URL = 'http://127.0.0.1:4000/graphql'; +const FUEL_NETWORK_URL = 'http://127.0.0.1:4000/v1/graphql'; /** * @group node @@ -62,7 +62,7 @@ describe('Provider', () => { const version = await provider.getVersion(); - expect(version).toEqual('0.22.1'); + expect(version).toEqual('0.23.0'); }); it('can call()', async () => { @@ -82,8 +82,9 @@ describe('Provider', () => { const callResult = await provider.call({ type: TransactionType.Script, - gasPrice: 0, - gasLimit: 1000000, + tip: 0, + gasLimit: 100, + maxFee: 100, script: /* Opcode::ADDI(0x10, REG_ZERO, 0xCA) @@ -135,7 +136,7 @@ describe('Provider', () => { const response = await provider.sendTransaction({ type: TransactionType.Script, - gasPrice: 0, + tip: 0, gasLimit: 1000000, script: /* @@ -943,7 +944,7 @@ describe('Provider', () => { }); it('should ensure calculateMaxgas considers gasLimit for ScriptTransactionRequest', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); - const { gasPerByte } = provider.getGasConfig(); + const { gasPerByte, maxGasPerTx } = provider.getGasConfig(); const gasLimit = bn(1000); const transactionRequest = new ScriptTransactionRequest({ @@ -963,6 +964,7 @@ describe('Provider', () => { expect(maxGasSpy).toHaveBeenCalledWith({ gasPerByte, minGas, + maxGasPerTx, witnessesLength, witnessLimit: transactionRequest.witnessLimit, gasLimit: transactionRequest.gasLimit, @@ -971,7 +973,7 @@ describe('Provider', () => { it('should ensure calculateMaxgas does NOT considers gasLimit for CreateTransactionRequest', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); - const { gasPerByte } = provider.getGasConfig(); + const { gasPerByte, maxGasPerTx } = provider.getGasConfig(); const transactionRequest = new CreateTransactionRequest({ witnesses: [ZeroBytes32], @@ -993,26 +995,25 @@ describe('Provider', () => { gasPerByte, minGas, witnessesLength, + maxGasPerTx, witnessLimit: transactionRequest.witnessLimit, }); }); - it('should ensure estimated fee values on getTransactionCost are never 0', async () => { + // TODO: validate if this test still makes sense + it.skip('should ensure estimated fee values on getTransactionCost are never 0', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const request = new ScriptTransactionRequest(); // forcing calculatePriceWithFactor to return 0 - const calculatePriceWithFactorMock = vi - .spyOn(gasMod, 'calculatePriceWithFactor') - .mockReturnValue(bn(0)); + const calculatePriceWithFactorMock = vi.spyOn(gasMod, 'calculateGasFee').mockReturnValue(bn(0)); - const { minFee, maxFee, usedFee } = await provider.getTransactionCost(request); + const { minFee, maxFee } = await provider.getTransactionCost(request); - expect(calculatePriceWithFactorMock).toHaveBeenCalledTimes(3); + expect(calculatePriceWithFactorMock).toHaveBeenCalledTimes(4); expect(maxFee.eq(0)).not.toBeTruthy(); - expect(usedFee.eq(0)).not.toBeTruthy(); expect(minFee.eq(0)).not.toBeTruthy(); }); diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index eef8e657006..62f5caad64c 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -1,7 +1,7 @@ import { Address } from '@fuel-ts/address'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { AbstractAccount, AbstractAddress, BytesLike } from '@fuel-ts/interfaces'; -import { BN, bn, max } from '@fuel-ts/math'; +import { BN, bn } from '@fuel-ts/math'; import type { Transaction } from '@fuel-ts/transactions'; import { InputType, @@ -22,9 +22,10 @@ import type { Predicate } from '../predicate'; import { getSdk as getOperationsSdk } from './__generated__/operations'; import type { GqlChainInfoFragmentFragment, + GqlDryRunFailureStatusFragmentFragment, + GqlDryRunSuccessStatusFragmentFragment, GqlGasCosts, GqlGetBlocksQueryVariables, - GqlPeerInfo, } from './__generated__/operations'; import type { Coin } from './coin'; import type { CoinQuantity, CoinQuantityLike } from './coin-quantity'; @@ -45,19 +46,20 @@ import { transactionRequestify } from './transaction-request'; import type { TransactionResultReceipt } from './transaction-response'; import { TransactionResponse } from './transaction-response'; import { processGqlReceipt } from './transaction-summary/receipt'; -import { - calculatePriceWithFactor, - getGasUsedFromReceipts, - getReceiptsWithMissingData, -} from './utils'; +import { calculateGasFee, getGasUsedFromReceipts, getReceiptsWithMissingData } from './utils'; import type { RetryOptions } from './utils/auto-retry-fetch'; import { autoRetryFetch } from './utils/auto-retry-fetch'; import { mergeQuantities } from './utils/merge-quantities'; const MAX_RETRIES = 10; +export type DryRunStatus = + | Omit + | Omit; + export type CallResult = { receipts: TransactionResultReceipt[]; + dryrunStatus?: DryRunStatus; }; export type EstimateTxDependenciesReturns = CallResult & { @@ -128,7 +130,6 @@ export type NodeInfo = { maxTx: BN; maxDepth: BN; nodeVersion: string; - peers: GqlPeerInfo[]; }; export type NodeInfoAndConsensusParameters = { @@ -141,19 +142,18 @@ export type NodeInfoAndConsensusParameters = { // #region cost-estimation-1 export type TransactionCost = { - requiredQuantities: CoinQuantity[]; - receipts: TransactionResultReceipt[]; - minGasPrice: BN; gasPrice: BN; - minGas: BN; - maxGas: BN; gasUsed: BN; + minGas: BN; minFee: BN; maxFee: BN; - usedFee: BN; + maxGas: BN; + receipts: TransactionResultReceipt[]; outputVariables: number; missingContractIds: string[]; - estimatedInputs: TransactionRequest['inputs']; + estimatedPredicates: TransactionRequestInput[]; + requiredQuantities: CoinQuantity[]; + addedSignatures: number; }; // #endregion cost-estimation-1 @@ -187,7 +187,7 @@ const processGqlChain = (chain: GqlChainInfoFragmentFragment): ChainInfo => { gasCosts, latestBlock: { id: latestBlock.id, - height: bn(latestBlock.header.height), + height: bn(latestBlock.height), time: latestBlock.header.time, transactions: latestBlock.transactions.map((i) => ({ id: i.id, @@ -259,16 +259,12 @@ export type EstimateTransactionParams = { estimateTxDependencies?: boolean; }; -export type EstimatePredicateParams = { - estimatePredicates?: boolean; +export type TransactionCostParams = EstimateTransactionParams & { + resourcesOwner?: AbstractAccount; + quantitiesToContract?: CoinQuantity[]; + signatureCallback?: (request: ScriptTransactionRequest) => Promise; }; -export type TransactionCostParams = EstimateTransactionParams & - EstimatePredicateParams & { - resourcesOwner?: AbstractAccount; - signatureCallback?: (request: ScriptTransactionRequest) => Promise; - }; - /** * Provider Call transaction params */ @@ -520,7 +516,7 @@ export default class Provider { */ async getBlockNumber(): Promise { const { chain } = await this.operations.getChain(); - return bn(chain.latestBlock.header.height, 10); + return bn(chain.latestBlock.height, 10); } /** @@ -538,7 +534,6 @@ export default class Provider { nodeVersion: nodeInfo.nodeVersion, utxoValidation: nodeInfo.utxoValidation, vmBacktrace: nodeInfo.vmBacktrace, - peers: nodeInfo.peers, }; Provider.nodeInfoCache[this.url] = processedNodeInfo; @@ -663,14 +658,14 @@ export default class Provider { return this.estimateTxDependencies(transactionRequest); } const encodedTransaction = hexlify(transactionRequest.toTransactionBytes()); - const { dryRun: gqlReceipts } = await this.operations.dryRun({ - encodedTransaction, + const { dryRun: dryRunStatuses } = await this.operations.dryRun({ + encodedTransactions: encodedTransaction, utxoValidation: utxoValidation || false, }); - const receipts = gqlReceipts.map(processGqlReceipt); - return { - receipts, - }; + const [{ receipts: rawReceipts, status }] = dryRunStatuses; + const receipts = rawReceipts.map(processGqlReceipt); + + return { receipts, dryrunStatus: status }; } /** @@ -720,9 +715,6 @@ export default class Provider { * If there are missing variable outputs, * `addVariableOutputs` is called on the transaction. * - * @privateRemarks - * TODO: Investigate support for missing contract IDs - * TODO: Add support for missing output messages * * @param transactionRequest - The transaction request object. * @returns A promise. @@ -738,18 +730,22 @@ export default class Provider { }; } - await this.estimatePredicates(transactionRequest); - let receipts: TransactionResultReceipt[] = []; const missingContractIds: string[] = []; let outputVariables = 0; + let dryrunStatus: DryRunStatus | undefined; for (let attempt = 0; attempt < MAX_RETRIES; attempt++) { - const { dryRun: gqlReceipts } = await this.operations.dryRun({ - encodedTransaction: hexlify(transactionRequest.toTransactionBytes()), + const { + dryRun: [{ receipts: rawReceipts, status }], + } = await this.operations.dryRun({ + encodedTransactions: [hexlify(transactionRequest.toTransactionBytes())], utxoValidation: false, }); - receipts = gqlReceipts.map(processGqlReceipt); + + receipts = rawReceipts.map(processGqlReceipt); + dryrunStatus = status; + const { missingOutputVariables, missingOutputContractIds } = getReceiptsWithMissingData(receipts); @@ -763,6 +759,14 @@ export default class Provider { transactionRequest.addContractInputAndOutput(Address.fromString(contractId)); missingContractIds.push(contractId); }); + + const { maxFee } = await this.estimateTxGasAndFee({ + transactionRequest, + optimizeGas: false, + }); + + // eslint-disable-next-line no-param-reassign + transactionRequest.maxFee = maxFee; } else { break; } @@ -772,6 +776,183 @@ export default class Provider { receipts, outputVariables, missingContractIds, + dryrunStatus, + }; + } + + /** + * Dry runs multiple transactions and checks for missing dependencies in batches. + * + * Transactions are dry run in batches. After each dry run, transactions requiring + * further modifications are identified. The method iteratively updates these transactions + * and performs subsequent dry runs until all dependencies for each transaction are satisfied. + * + * @param transactionRequests - Array of transaction request objects. + * @returns A promise that resolves to an array of results for each transaction. + */ + async estimateMultipleTxDependencies( + transactionRequests: TransactionRequest[] + ): Promise { + const results: EstimateTxDependenciesReturns[] = transactionRequests.map(() => ({ + receipts: [], + outputVariables: 0, + missingContractIds: [], + dryrunStatus: undefined, + })); + + const allRequests = clone(transactionRequests); + + // Map of original request index to its serialized transaction (for ScriptTransactionRequest only) + const serializedTransactionsMap = new Map(); + + // Prepare ScriptTransactionRequests and their indices + allRequests.forEach((req, index) => { + if (req.type === TransactionType.Script) { + serializedTransactionsMap.set(index, hexlify(req.toTransactionBytes())); + } + }); + + // Indices of ScriptTransactionRequests + let transactionsToProcess = Array.from(serializedTransactionsMap.keys()); + let attempt = 0; + + while (transactionsToProcess.length > 0 && attempt < MAX_RETRIES) { + const encodedTransactions = transactionsToProcess.map((index) => + serializedTransactionsMap.get(index) + ); + const dryRunResults = await this.operations.dryRun({ + encodedTransactions, + utxoValidation: false, + }); + + const nextRoundTransactions = []; + + for (let i = 0; i < dryRunResults.dryRun.length; i++) { + const currentResultIndex = transactionsToProcess[i]; + const { receipts: rawReceipts, status } = dryRunResults.dryRun[i]; + results[currentResultIndex].receipts = rawReceipts.map(processGqlReceipt); + results[currentResultIndex].dryrunStatus = status; + + const { missingOutputVariables, missingOutputContractIds } = getReceiptsWithMissingData( + results[currentResultIndex].receipts + ); + const hasMissingOutputs = + missingOutputVariables.length > 0 || missingOutputContractIds.length > 0; + + const requestToProcess = allRequests[currentResultIndex]; + + if (hasMissingOutputs && requestToProcess?.type === TransactionType.Script) { + results[currentResultIndex].outputVariables += missingOutputVariables.length; + requestToProcess.addVariableOutputs(missingOutputVariables.length); + missingOutputContractIds.forEach(({ contractId }) => { + requestToProcess.addContractInputAndOutput(Address.fromString(contractId)); + results[currentResultIndex].missingContractIds.push(contractId); + }); + + const { maxFee } = await this.estimateTxGasAndFee({ + transactionRequest: requestToProcess, + optimizeGas: false, + }); + requestToProcess.maxFee = maxFee; + + // Prepare for the next round of dry run + serializedTransactionsMap.set( + currentResultIndex, + hexlify(requestToProcess.toTransactionBytes()) + ); + nextRoundTransactions.push(currentResultIndex); + + allRequests[currentResultIndex] = requestToProcess; + } + } + + transactionsToProcess = nextRoundTransactions; + attempt += 1; + } + + return results; + } + + async dryRunMultipleTransactions( + transactionRequests: TransactionRequest[], + { utxoValidation, estimateTxDependencies = true }: ProviderCallParams = {} + ): Promise { + if (estimateTxDependencies) { + return this.estimateMultipleTxDependencies(transactionRequests); + } + const encodedTransactions = transactionRequests.map((tx) => hexlify(tx.toTransactionBytes())); + const { dryRun: dryRunStatuses } = await this.operations.dryRun({ + encodedTransactions, + utxoValidation: utxoValidation || false, + }); + + const results = dryRunStatuses.map(({ receipts: rawReceipts, status }) => { + const receipts = rawReceipts.map(processGqlReceipt); + return { receipts, dryrunStatus: status }; + }); + + return results; + } + + async estimateTxGasAndFee(params: { + transactionRequest: TransactionRequest; + optimizeGas?: boolean; + totalGasUsedByPredicates?: BN; + gasPrice?: BN; + }) { + const { transactionRequest, totalGasUsedByPredicates = bn(0), optimizeGas = true } = params; + let { gasPrice } = params; + + const chainInfo = this.getChain(); + + const { gasPriceFactor } = this.getGasConfig(); + + const minGas = transactionRequest.calculateMinGas(chainInfo); + + if (!gasPrice) { + gasPrice = await this.estimateGasPrice(10); + } + + const shouldSetGaslimit = transactionRequest.type === TransactionType.Script && !optimizeGas; + + const minFee = calculateGasFee({ + gasPrice: bn(gasPrice), + gas: minGas, + priceFactor: gasPriceFactor, + tip: transactionRequest.tip, + }).add(1); + + if (shouldSetGaslimit) { + transactionRequest.gasLimit = chainInfo.consensusParameters.maxGasPerTx.sub( + minGas.add(totalGasUsedByPredicates) + ); + } + + let maxGas = transactionRequest.calculateMaxGas(chainInfo, minGas); + + const maxFee = calculateGasFee({ + gasPrice: bn(gasPrice), + gas: maxGas, + priceFactor: gasPriceFactor, + tip: transactionRequest.tip, + }).add(1); + + if (shouldSetGaslimit) { + /** + * NOTE: The dry estimate TX might fail if it uses a gas value higher that the "gaslimit". + * Therefore, we need to set it as the highest value possible. The sum of "gasLimit" and + * "gasFee" cannot be higher than "maxGasPerTx". + */ + maxGas = chainInfo.consensusParameters.maxGasPerTx.sub(maxFee); + transactionRequest.gasLimit = maxGas; + } + + return { + minGas, + minFee, + maxGas, + maxFee, + gasPrice, }; } @@ -793,15 +974,22 @@ export default class Provider { if (estimateTxDependencies) { return this.estimateTxDependencies(transactionRequest); } - const encodedTransaction = hexlify(transactionRequest.toTransactionBytes()); - const { dryRun: gqlReceipts } = await this.operations.dryRun({ - encodedTransaction, + const encodedTransactions = [hexlify(transactionRequest.toTransactionBytes())]; + + const { dryRun: dryRunStatuses } = await this.operations.dryRun({ + encodedTransactions, utxoValidation: true, }); - const receipts = gqlReceipts.map(processGqlReceipt); - return { - receipts, - }; + + const callResult = dryRunStatuses.map((dryRunStatus) => { + const { id, receipts, status } = dryRunStatus; + + const processedReceipts = receipts.map(processGqlReceipt); + + return { id, receipts: processedReceipts, status }; + }); + + return { receipts: callResult[0].receipts }; } /** @@ -821,123 +1009,111 @@ export default class Provider { */ async getTransactionCost( transactionRequestLike: TransactionRequestLike, - forwardingQuantities: CoinQuantity[] = [], - { - estimateTxDependencies = true, - estimatePredicates = true, - resourcesOwner, - signatureCallback, - }: TransactionCostParams = {} + { resourcesOwner, signatureCallback, quantitiesToContract = [] }: TransactionCostParams = {} ): Promise { const txRequestClone = clone(transactionRequestify(transactionRequestLike)); - const chainInfo = this.getChain(); - const { gasPriceFactor, minGasPrice, maxGasPerTx } = this.getGasConfig(); - const gasPrice = max(txRequestClone.gasPrice, minGasPrice); const isScriptTransaction = txRequestClone.type === TransactionType.Script; // Fund with fake UTXOs to avoid not enough funds error // Getting coin quantities from amounts being transferred const coinOutputsQuantities = txRequestClone.getCoinOutputsQuantities(); // Combining coin quantities from amounts being transferred and forwarding to contracts - const allQuantities = mergeQuantities(coinOutputsQuantities, forwardingQuantities); + const allQuantities = mergeQuantities(coinOutputsQuantities, quantitiesToContract); // Funding transaction with fake utxos txRequestClone.fundWithFakeUtxos(allQuantities, resourcesOwner?.address); /** * Estimate predicates gasUsed */ - if (estimatePredicates) { - // Remove gasLimit to avoid gasLimit when estimating predicates - if (isScriptTransaction) { - txRequestClone.gasLimit = bn(0); - } + // Remove gasLimit to avoid gasLimit when estimating predicates + txRequestClone.maxFee = bn(0); + if (isScriptTransaction) { + txRequestClone.gasLimit = bn(0); + } - /** - * The fake utxos added above can be from a predicate - * If the resources owner is a predicate, - * we need to populate the resources with the predicate's data - * so that predicate estimation can happen. - */ - if (resourcesOwner && 'populateTransactionPredicateData' in resourcesOwner) { - (resourcesOwner as Predicate<[]>).populateTransactionPredicateData(txRequestClone); - } - await this.estimatePredicates(txRequestClone); + /** + * The fake utxos added above can be from a predicate + * If the resources owner is a predicate, + * we need to populate the resources with the predicate's data + * so that predicate estimation can happen. + */ + if (resourcesOwner && 'populateTransactionPredicateData' in resourcesOwner) { + (resourcesOwner as Predicate<[]>).populateTransactionPredicateData(txRequestClone); } + const signedRequest = clone(txRequestClone) as ScriptTransactionRequest; + + let addedSignatures = 0; if (signatureCallback && isScriptTransaction) { - await signatureCallback(txRequestClone); + const lengthBefore = signedRequest.witnesses.length; + await signatureCallback(signedRequest); + addedSignatures = signedRequest.witnesses.length - lengthBefore; } + await this.estimatePredicates(signedRequest); + /** * Calculate minGas and maxGas based on the real transaction */ - const minGas = txRequestClone.calculateMinGas(chainInfo); - const maxGas = txRequestClone.calculateMaxGas(chainInfo, minGas); + let { maxFee, maxGas, minFee, minGas, gasPrice } = await this.estimateTxGasAndFee({ + transactionRequest: signedRequest, + optimizeGas: false, + }); - /** - * Estimate gasUsed for script transactions - */ + txRequestClone.maxFee = maxFee; let receipts: TransactionResultReceipt[] = []; let missingContractIds: string[] = []; let outputVariables = 0; - // Transactions of type Create does not consume any gas so we can the dryRun - if (isScriptTransaction && estimateTxDependencies) { - /** - * Setting the gasPrice to 0 on a dryRun will result in no fees being charged. - * This simplifies the funding with fake utxos, since the coin quantities required - * will only be amounts being transferred (coin outputs) and amounts being forwarded - * to contract calls. - */ - // Calculate the gasLimit again as we insert a fake UTXO and signer + let gasUsed = bn(0); - txRequestClone.gasPrice = bn(0); - txRequestClone.gasLimit = bn(maxGasPerTx.sub(maxGas).toNumber() * 0.9); + txRequestClone.updatePredicateGasUsed(signedRequest.inputs); - // Executing dryRun with fake utxos to get gasUsed + if (isScriptTransaction) { + if (signatureCallback) { + await signatureCallback(txRequestClone); + } + txRequestClone.gasLimit = maxGas; const result = await this.estimateTxDependencies(txRequestClone); - receipts = result.receipts; outputVariables = result.outputVariables; missingContractIds = result.missingContractIds; - } + gasUsed = getGasUsedFromReceipts(receipts); - // For CreateTransaction the gasUsed is going to be the minGas - const gasUsed = isScriptTransaction ? getGasUsedFromReceipts(receipts) : minGas; + txRequestClone.gasLimit = gasUsed; - const usedFee = calculatePriceWithFactor( - gasUsed, - gasPrice, - gasPriceFactor - ).normalizeZeroToOne(); - const minFee = calculatePriceWithFactor(minGas, gasPrice, gasPriceFactor).normalizeZeroToOne(); - const maxFee = calculatePriceWithFactor(maxGas, gasPrice, gasPriceFactor).normalizeZeroToOne(); + ({ maxFee, maxGas, minFee, minGas, gasPrice } = await this.estimateTxGasAndFee({ + transactionRequest: txRequestClone, + gasPrice, + })); + } return { requiredQuantities: allQuantities, receipts, gasUsed, - minGasPrice, gasPrice, minGas, maxGas, - usedFee, minFee, maxFee, - estimatedInputs: txRequestClone.inputs, outputVariables, missingContractIds, + addedSignatures, + estimatedPredicates: txRequestClone.inputs, }; } async getResourcesForTransaction( owner: string | AbstractAddress, transactionRequestLike: TransactionRequestLike, - forwardingQuantities: CoinQuantity[] = [] + quantitiesToContract: CoinQuantity[] = [] ) { const ownerAddress = Address.fromAddressOrString(owner); const transactionRequest = transactionRequestify(clone(transactionRequestLike)); - const transactionCost = await this.getTransactionCost(transactionRequest, forwardingQuantities); + const transactionCost = await this.getTransactionCost(transactionRequest, { + quantitiesToContract, + }); // Add the required resources to the transaction from the owner transactionRequest.addResources( @@ -949,10 +1125,9 @@ export default class Provider { // Also for the dryRun we could have the same issue as we are going to run twice the dryRun and the // estimateTxDependencies as we don't have access to the transaction, maybe returning the transaction would // be better. - const { requiredQuantities, ...txCost } = await this.getTransactionCost( - transactionRequest, - forwardingQuantities - ); + const { requiredQuantities, ...txCost } = await this.getTransactionCost(transactionRequest, { + quantitiesToContract, + }); const resources = await this.getResourcesToSpend(ownerAddress, requiredQuantities); return { @@ -987,7 +1162,6 @@ export default class Provider { assetId: coin.assetId, amount: bn(coin.amount), owner: Address.fromAddressOrString(coin.owner), - maturity: bn(coin.maturity).toNumber(), blockCreated: bn(coin.blockCreated), txCreatedIdx: bn(coin.txCreatedIdx), })); @@ -1054,7 +1228,6 @@ export default class Provider { amount: bn(coin.amount), assetId: coin.assetId, owner: Address.fromAddressOrString(coin.owner), - maturity: bn(coin.maturity).toNumber(), blockCreated: bn(coin.blockCreated), txCreatedIdx: bn(coin.txCreatedIdx), } as Coin; @@ -1096,7 +1269,7 @@ export default class Provider { return { id: block.id, - height: bn(block.header.height), + height: bn(block.height), time: block.header.time, transactionIds: block.transactions.map((tx) => tx.id), }; @@ -1113,7 +1286,7 @@ export default class Provider { const blocks: Block[] = fetchedData.edges.map(({ node: block }) => ({ id: block.id, - height: bn(block.header.height), + height: bn(block.height), time: block.header.time, transactionIds: block.transactions.map((tx) => tx.id), })); @@ -1148,7 +1321,7 @@ export default class Provider { return { id: block.id, - height: bn(block.header.height, 10), + height: bn(block.height, 10), time: block.header.time, transactionIds: block.transactions.map((tx) => tx.id), transactions: block.transactions.map( @@ -1404,6 +1577,18 @@ export default class Provider { }; } + async getLatestGasPrice(): Promise { + const { latestGasPrice } = await this.operations.getLatestGasPrice(); + return bn(latestGasPrice.gasPrice); + } + + async estimateGasPrice(blockHorizon: number): Promise { + const { estimateGasPrice } = await this.operations.estimateGasPrice({ + blockHorizon: String(blockHorizon), + }); + return bn(estimateGasPrice.gasPrice); + } + /** * Returns Message Proof for given transaction id and the message id from MessageOut receipt. * diff --git a/packages/account/src/providers/transaction-request/hash-transaction.test.ts b/packages/account/src/providers/transaction-request/hash-transaction.test.ts index b09b282c757..dbd5fa09a5d 100644 --- a/packages/account/src/providers/transaction-request/hash-transaction.test.ts +++ b/packages/account/src/providers/transaction-request/hash-transaction.test.ts @@ -11,7 +11,7 @@ import { hashTransaction } from './hash-transaction'; describe('hashTransaction', () => { it('Hash script transaction request', () => { expect(hashTransaction(SCRIPT_TX_REQUEST, 0)).toEqual( - '0x7645fa2154ee610469ebc876d0cb7b6fcf390fb97f2c6b88a2344cc23533fa39' + '0xef06f034adc08aff5ae3c078b7248798ab2c6e1b762f3a631e3e202067ff686f' ); }); @@ -35,7 +35,7 @@ describe('hashTransaction', () => { ]; expect(hashTransaction(txRequest, 0)).toEqual( - '0xf3f6ef8a9e6a495fbe4998d8cb197550aecf1eb9e89ce10cf13a8b03bd4dfb6a' + '0x1eeee0608173f11d4761a868555d9c8cfe141cd36d1becc95bc1bc656721969f' ); }); }); diff --git a/packages/account/src/providers/transaction-request/input.ts b/packages/account/src/providers/transaction-request/input.ts index 947f8cabb3e..610a14732a2 100644 --- a/packages/account/src/providers/transaction-request/input.ts +++ b/packages/account/src/providers/transaction-request/input.ts @@ -28,9 +28,6 @@ export type CoinTransactionRequestInput = { /** Index of witness that authorizes spending the coin */ witnessIndex: number; - /** UTXO being spent must have been created at least this many blocks ago */ - maturity?: number; - /** Gas used by predicate */ predicateGasUsed?: BigNumberish; @@ -39,6 +36,8 @@ export type CoinTransactionRequestInput = { /** Predicate input data (parameters) */ predicateData?: BytesLike; + + paddPredicateData?: (policiesLenght: number) => BytesLike; }; export type MessageTransactionRequestInput = { @@ -68,6 +67,8 @@ export type MessageTransactionRequestInput = { /** Predicate input data (parameters) */ predicateData?: BytesLike; + paddPredicateData?: (policiesLenght: number) => BytesLike; + /** data of message */ data?: BytesLike; }; @@ -106,7 +107,6 @@ export const inputify = (value: TransactionRequestInput): Input => { txIndex: toNumber(arrayify(value.txPointer).slice(8, 16)), }, witnessIndex: value.witnessIndex, - maturity: value.maturity ?? 0, predicateGasUsed: bn(value.predicateGasUsed), predicateLength: predicate.length, predicateDataLength: predicateData.length, diff --git a/packages/account/src/providers/transaction-request/script-transaction-request.ts b/packages/account/src/providers/transaction-request/script-transaction-request.ts index 4195824f820..75cb1ac3d1c 100644 --- a/packages/account/src/providers/transaction-request/script-transaction-request.ts +++ b/packages/account/src/providers/transaction-request/script-transaction-request.ts @@ -155,7 +155,7 @@ export class ScriptTransactionRequest extends BaseTransactionRequest { calculateMaxGas(chainInfo: ChainInfo, minGas: BN): BN { const { consensusParameters } = chainInfo; - const { gasPerByte } = consensusParameters; + const { gasPerByte, maxGasPerTx } = consensusParameters; const witnessesLength = this.toTransaction().witnesses.reduce( (acc, wit) => acc + wit.dataLength, @@ -168,6 +168,7 @@ export class ScriptTransactionRequest extends BaseTransactionRequest { witnessesLength, witnessLimit: this.witnessLimit, gasLimit: this.gasLimit, + maxGasPerTx, }); } diff --git a/packages/account/src/providers/transaction-request/transaction-request.test.ts b/packages/account/src/providers/transaction-request/transaction-request.test.ts index d348a9927a0..1b3b33d0333 100644 --- a/packages/account/src/providers/transaction-request/transaction-request.test.ts +++ b/packages/account/src/providers/transaction-request/transaction-request.test.ts @@ -77,7 +77,7 @@ describe('TransactionRequest', () => { expect(inputA?.amount).toEqual(bn(700)); expect(inputB?.amount).toEqual(bn(300)); - expect(inputBase?.amount).toEqual(bn(500)); + expect(inputBase?.amount).toEqual(bn('1000000000000000000')); }); it('updates witnesses', () => { @@ -88,7 +88,6 @@ describe('TransactionRequest', () => { owner: coinOwner, amount: bn(100), assetId: ASSET_A, - maturity: 0, blockCreated: bn(0), txCreatedIdx: bn(0), }; @@ -159,7 +158,7 @@ describe('transactionRequestify', () => { type: TransactionType.Script, script, scriptData, - gasPrice: 1, + tip: 1, gasLimit: 10000, maturity: 1, inputs: [], @@ -174,7 +173,7 @@ describe('transactionRequestify', () => { } expect(txRequest.type).toEqual(txRequestLike.type); - expect(toNumber(txRequest.gasPrice)).toEqual(txRequestLike.gasPrice); + expect(toNumber(txRequest.tip)).toEqual(txRequestLike.tip); expect(toNumber((txRequest).gasLimit)).toEqual( txRequestLike.gasLimit ); @@ -187,7 +186,6 @@ describe('transactionRequestify', () => { it('should throw error if invalid transaction type', () => { const txRequestLike = { type: 5, - gasPrice: 1, }; expect(() => transactionRequestify(txRequestLike)).toThrow('Invalid transaction type: 5'); diff --git a/packages/account/src/providers/transaction-request/transaction-request.ts b/packages/account/src/providers/transaction-request/transaction-request.ts index a112056babe..cb3f6419914 100644 --- a/packages/account/src/providers/transaction-request/transaction-request.ts +++ b/packages/account/src/providers/transaction-request/transaction-request.ts @@ -1,4 +1,3 @@ -import type { InputValue } from '@fuel-ts/abi-coder'; import { Address, addressify } from '@fuel-ts/address'; import { BaseAssetId, ZeroBytes32 } from '@fuel-ts/address/configs'; import type { AddressLike, AbstractAddress, BytesLike } from '@fuel-ts/interfaces'; @@ -13,9 +12,9 @@ import { TransactionType, } from '@fuel-ts/transactions'; import { concat, hexlify } from '@fuel-ts/utils'; +import { randomBytes } from 'ethers'; import type { Account } from '../../account'; -import type { Predicate } from '../../predicate'; import type { GqlGasCosts } from '../__generated__/operations'; import type { Coin } from '../coin'; import type { CoinQuantity, CoinQuantityLike } from '../coin-quantity'; @@ -58,7 +57,7 @@ export { */ export interface BaseTransactionRequestLike { /** Gas price for transaction */ - gasPrice?: BigNumberish; + tip?: BigNumberish; /** Block until which tx cannot be included */ maturity?: number; /** The maximum fee payable by this transaction using BASE_ASSET. */ @@ -92,7 +91,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi /** Type of the transaction */ abstract type: TransactionType; /** Gas price for transaction */ - gasPrice: BN; + tip: BN; /** Block until which tx cannot be included */ maturity: number; /** The maximum fee payable by this transaction using BASE_ASSET. */ @@ -112,7 +111,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi * @param baseTransactionRequest - Optional object containing properties to initialize the transaction request. */ constructor({ - gasPrice, + tip, maturity, maxFee, witnessLimit, @@ -120,7 +119,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi outputs, witnesses, }: BaseTransactionRequestLike = {}) { - this.gasPrice = bn(gasPrice); + this.tip = bn(tip); this.maturity = maturity ?? 0; this.witnessLimit = witnessLimit ? bn(witnessLimit) : undefined; this.maxFee = maxFee ? bn(maxFee) : undefined; @@ -133,9 +132,9 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi let policyTypes = 0; const policies: Policy[] = []; - if (req.gasPrice) { - policyTypes += PolicyType.GasPrice; - policies.push({ data: req.gasPrice, type: PolicyType.GasPrice }); + if (req.tip) { + policyTypes += PolicyType.Tip; + policies.push({ data: req.tip, type: PolicyType.Tip }); } if (req.witnessLimit) { policyTypes += PolicyType.WitnessLimit; @@ -232,7 +231,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi * * @returns The index of the created witness. */ - protected addEmptyWitness(): number { + addEmptyWitness(): number { // Push a dummy witness with same byte size as a real witness signature this.addWitness(concat([ZeroBytes32, ZeroBytes32])); return this.witnesses.length - 1; @@ -348,12 +347,12 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi * @param predicate - Predicate bytes. * @param predicateData - Predicate data bytes. */ - addCoinInput(coin: Coin, predicate?: Predicate) { + addCoinInput(coin: Coin) { const { assetId, owner, amount } = coin; let witnessIndex; - if (predicate) { + if (coin.predicate) { witnessIndex = 0; } else { witnessIndex = this.getCoinInputWitnessIndexByOwner(owner); @@ -372,8 +371,6 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi assetId, txPointer: '0x00000000000000000000000000000000', witnessIndex, - predicate: predicate?.bytes, - predicateData: predicate?.predicateDataBytes, }; // Insert the Input @@ -391,14 +388,14 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi * @param predicate - Predicate bytes. * @param predicateData - Predicate data bytes. */ - addMessageInput(message: MessageCoin, predicate?: Predicate) { + addMessageInput(message: MessageCoin) { const { recipient, sender, amount } = message; const assetId = BaseAssetId; let witnessIndex; - if (predicate) { + if (message.predicate) { witnessIndex = 0; } else { witnessIndex = this.getCoinInputWitnessIndexByOwner(recipient); @@ -416,8 +413,6 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi recipient: recipient.toB256(), amount, witnessIndex, - predicate: predicate?.bytes, - predicateData: predicate?.predicateDataBytes, }; // Insert the Input @@ -457,36 +452,6 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi return this; } - /** - * Adds multiple resources to the transaction by adding coin/message inputs and change - * outputs from the related assetIds. - * - * @param resources - The resources to add. - * @returns This transaction. - */ - addPredicateResource(resource: Resource, predicate: Predicate) { - if (isCoin(resource)) { - this.addCoinInput(resource, predicate); - } else { - this.addMessageInput(resource, predicate); - } - - return this; - } - - /** - * Adds multiple predicate coin/message inputs to the transaction and change outputs - * from the related assetIds. - * - * @param resources - The resources to add. - * @returns This transaction. - */ - addPredicateResources(resources: Resource[], predicate: Predicate) { - resources.forEach((resource) => this.addPredicateResource(resource, predicate)); - - return this; - } - /** * Adds a coin output to the transaction. * @@ -577,7 +542,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi calculateMaxGas(chainInfo: ChainInfo, minGas: BN): BN { const { consensusParameters } = chainInfo; - const { gasPerByte } = consensusParameters; + const { gasPerByte, maxGasPerTx } = consensusParameters; const witnessesLength = this.toTransaction().witnesses.reduce( (acc, wit) => acc + wit.dataLength, @@ -588,6 +553,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi minGas, witnessesLength, witnessLimit: this.witnessLimit, + maxGasPerTx, }); } @@ -598,13 +564,6 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi * @param quantities - CoinQuantity Array. */ fundWithFakeUtxos(quantities: CoinQuantity[], resourcesOwner?: AbstractAddress) { - let idCounter = 0; - const generateId = (): string => { - const counterString = String(idCounter++); - const id = ZeroBytes32.slice(0, -counterString.length).concat(counterString); - return id; - }; - const findAssetInput = (assetId: string) => this.inputs.find((input) => { if ('assetId' in input) { @@ -616,17 +575,22 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi const updateAssetInput = (assetId: string, quantity: BN) => { const assetInput = findAssetInput(assetId); + let usedQuantity = quantity; + + if (assetId === BaseAssetId) { + usedQuantity = bn('1000000000000000000'); + } + if (assetInput && 'assetId' in assetInput) { - assetInput.id = generateId(); - assetInput.amount = quantity; + assetInput.id = hexlify(randomBytes(33)); + assetInput.amount = usedQuantity; } else { this.addResources([ { - id: generateId(), - amount: quantity, + id: hexlify(randomBytes(33)), + amount: usedQuantity, assetId, owner: resourcesOwner || Address.fromRandom(), - maturity: 0, blockCreated: bn(1), txCreatedIdx: bn(1), }, @@ -672,7 +636,7 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi return normalizeJSON(this); } - updatePredicateInputs(inputs: TransactionRequestInput[]) { + updatePredicateGasUsed(inputs: TransactionRequestInput[]) { this.inputs.forEach((i) => { let correspondingInput: TransactionRequestInput | undefined; switch (i.type) { @@ -701,4 +665,20 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi } }); } + + shiftPredicateData() { + this.inputs.forEach((input) => { + // TODO: improve logic + if ( + 'predicateData' in input && + 'paddPredicateData' in input && + typeof input.paddPredicateData === 'function' + ) { + // eslint-disable-next-line no-param-reassign + input.predicateData = input.paddPredicateData( + BaseTransactionRequest.getPolicyMeta(this).policies.length + ); + } + }); + } } diff --git a/packages/account/src/providers/transaction-request/utils.ts b/packages/account/src/providers/transaction-request/utils.ts index d89de4772cb..fec2472cba2 100644 --- a/packages/account/src/providers/transaction-request/utils.ts +++ b/packages/account/src/providers/transaction-request/utils.ts @@ -1,7 +1,10 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; -import { TransactionType } from '@fuel-ts/transactions'; +import { TransactionType, InputType } from '@fuel-ts/transactions'; + +import type { ExcludeResourcesOption } from '../resource'; import { CreateTransactionRequest } from './create-transaction-request'; +import type { TransactionRequestInput } from './input'; import { ScriptTransactionRequest } from './script-transaction-request'; import type { TransactionRequestLike, TransactionRequest } from './types'; @@ -25,3 +28,25 @@ export const transactionRequestify = (obj: TransactionRequestLike): TransactionR } } }; + +export const cacheTxInputsFromOwner = ( + inputs: TransactionRequestInput[], + owner: string +): ExcludeResourcesOption => + inputs.reduce( + (acc, input) => { + if (input.type === InputType.Coin && input.owner === owner) { + acc.utxos.push(input.id); + } + + if (input.type === InputType.Message && input.recipient === owner) { + acc.messages.push(input.nonce); + } + + return acc; + }, + { + utxos: [], + messages: [], + } as Required + ); diff --git a/packages/account/src/providers/transaction-response/transaction-response.ts b/packages/account/src/providers/transaction-response/transaction-response.ts index 21e0f17a54d..b715cd90ded 100644 --- a/packages/account/src/providers/transaction-response/transaction-response.ts +++ b/packages/account/src/providers/transaction-response/transaction-response.ts @@ -20,6 +20,7 @@ import type { import { TransactionCoder } from '@fuel-ts/transactions'; import { arrayify } from '@fuel-ts/utils'; +import type { GqlReceiptFragmentFragment } from '../__generated__/operations'; import type Provider from '../provider'; import type { JsonAbisFromAllCalls } from '../transaction-request'; import { assembleTransactionSummary } from '../transaction-summary/assemble-transaction-summary'; @@ -183,9 +184,16 @@ export class TransactionResponse { transaction ) as Transaction; - const receipts = transaction.receipts?.map(processGqlReceipt) || []; + let txReceipts: GqlReceiptFragmentFragment[] = []; - const { gasPerByte, gasPriceFactor, gasCosts } = this.provider.getGasConfig(); + if (transaction?.status && 'receipts' in transaction.status) { + txReceipts = transaction.status.receipts; + } + + const receipts = txReceipts.map(processGqlReceipt) || []; + + const { gasPerByte, gasPriceFactor, gasCosts, maxGasPerTx } = this.provider.getGasConfig(); + const gasPrice = await this.provider.getLatestGasPrice(); const maxInputs = this.provider.getChain().consensusParameters.maxInputs; const transactionSummary = assembleTransactionSummary({ @@ -199,6 +207,8 @@ export class TransactionResponse { abiMap: contractsAbiMap, maxInputs, gasCosts, + maxGasPerTx, + gasPrice, }); return transactionSummary; diff --git a/packages/account/src/providers/transaction-summary/assemble-transaction-summary.test.ts b/packages/account/src/providers/transaction-summary/assemble-transaction-summary.test.ts index 1c8af328191..9c7234802aa 100644 --- a/packages/account/src/providers/transaction-summary/assemble-transaction-summary.test.ts +++ b/packages/account/src/providers/transaction-summary/assemble-transaction-summary.test.ts @@ -33,6 +33,7 @@ describe('TransactionSummary', () => { const gasPerByte = bn(2); const gasPriceFactor = bn(3); const maxInputs = bn(255); + const maxGasPerTx = bn(10000000); const transaction = MOCK_TRANSACTION; const transactionBytes = arrayify(MOCK_TRANSACTION_RAWPAYLOAD); const receipts: TransactionResultReceipt[] = [ @@ -44,7 +45,7 @@ describe('TransactionSummary', () => { ]; beforeAll(async () => { - provider = await Provider.create('http://127.0.0.1:4000/graphql'); + provider = await Provider.create('http://127.0.0.1:4000/v1/graphql'); gasCosts = provider.getChain().gasCosts; }); @@ -59,7 +60,6 @@ describe('TransactionSummary', () => { fee: bn(0), minFee: bn(0), maxFee: bn(0), - feeFromGasUsed: bn(0), }); return { @@ -81,6 +81,8 @@ describe('TransactionSummary', () => { maxInputs, gasCosts, abiMap: {}, + maxGasPerTx, + gasPrice: bn(1), }); expect(transactionSummary).toMatchObject(expected); diff --git a/packages/account/src/providers/transaction-summary/assemble-transaction-summary.ts b/packages/account/src/providers/transaction-summary/assemble-transaction-summary.ts index 9df69cc11b0..b1eca0ebc9c 100644 --- a/packages/account/src/providers/transaction-summary/assemble-transaction-summary.ts +++ b/packages/account/src/providers/transaction-summary/assemble-transaction-summary.ts @@ -1,5 +1,5 @@ -import { type BN } from '@fuel-ts/math'; -import { type Transaction } from '@fuel-ts/transactions'; +import { bn, type BN } from '@fuel-ts/math'; +import { PolicyType, type Transaction } from '@fuel-ts/transactions'; import { DateTime, hexlify } from '@fuel-ts/utils'; import type { GqlGasCosts } from '../__generated__/operations'; @@ -29,6 +29,8 @@ export interface AssembleTransactionSummaryParams { abiMap?: AbiMap; maxInputs: BN; gasCosts: GqlGasCosts; + maxGasPerTx: BN; + gasPrice: BN; } /** @hidden */ @@ -46,6 +48,8 @@ export function assembleTransactionSummary( abiMap = {}, maxInputs, gasCosts, + maxGasPerTx, + gasPrice, } = params; const gasUsed = getGasUsedFromReceipts(receipts); @@ -64,11 +68,15 @@ export function assembleTransactionSummary( const typeName = getTransactionTypeName(transaction.type); + const tip = bn(transaction.policies?.find((policy) => policy.type === PolicyType.Tip)?.data); + const { fee } = calculateTransactionFee({ - gasUsed, + gasPrice, rawPayload, + tip, consensusParameters: { gasCosts, + maxGasPerTx, feeParams: { gasPerByte, gasPriceFactor, diff --git a/packages/account/src/providers/transaction-summary/calculate-transaction-fee.test.ts b/packages/account/src/providers/transaction-summary/calculate-transaction-fee.test.ts index bea33b011fe..6b6bfd5dec1 100644 --- a/packages/account/src/providers/transaction-summary/calculate-transaction-fee.test.ts +++ b/packages/account/src/providers/transaction-summary/calculate-transaction-fee.test.ts @@ -15,85 +15,95 @@ import { calculateTransactionFee } from './calculate-transaction-fee'; describe('calculateTransactionFee', () => { it('should properly calculate the transaction fee (SCRIPT TX)', () => { const transactionRawPayload = MOCK_TX_SCRIPT_RAW_PAYLOAD; - const { gasCosts } = MOCK_CHAIN.consensusParameters; + const { + gasCosts, + txParams: { maxGasPerTx }, + } = MOCK_CHAIN.consensusParameters; const gasPriceFactor = 92; const gasPerByte = 4; - const { fee, feeFromGasUsed, maxFee, minFee } = calculateTransactionFee({ + const { fee, maxFee, minFee } = calculateTransactionFee({ + tip: bn(0), + gasPrice: bn(1), consensusParameters: { feeParams: { gasPriceFactor, gasPerByte, }, + maxGasPerTx: bn(maxGasPerTx), gasCosts, }, - gasUsed: bn(1), rawPayload: transactionRawPayload, }); - const expectedfee = bn(90); - const expectedfeeFromGasUsed = bn(1); - const expectedmaxFee = bn(198); - const expectedminFee = bn(89); + const expectedfee = bn(197); + const expectedmaxFee = bn(197); + const expectedminFee = bn(88); expect(fee.toNumber()).toEqual(expectedfee.toNumber()); - expect(feeFromGasUsed.toNumber()).toEqual(expectedfeeFromGasUsed.toNumber()); expect(maxFee.toNumber()).toEqual(expectedmaxFee.toNumber()); expect(minFee.toNumber()).toEqual(expectedminFee.toNumber()); }); it('should properly calculate the transaction fee (CREATE TX)', () => { const transactionRawPayload = MOCK_TX_CREATE_RAW_PAYLOAD; - const { gasCosts } = MOCK_CHAIN.consensusParameters; + const { + gasCosts, + txParams: { maxGasPerTx }, + } = MOCK_CHAIN.consensusParameters; const gasPriceFactor = 92; const gasPerByte = 4; - const { fee, feeFromGasUsed, maxFee, minFee } = calculateTransactionFee({ + const { fee, maxFee, minFee } = calculateTransactionFee({ + tip: bn(0), + gasPrice: bn(1), consensusParameters: { feeParams: { gasPriceFactor, gasPerByte, }, + maxGasPerTx: bn(maxGasPerTx), gasCosts, }, - gasUsed: bn(1), rawPayload: transactionRawPayload, }); - const expectedfee = bn(88); - const expectedfeeFromGasUsed = bn(1); - const expectedmaxFee = bn(87); - const expectedminFee = bn(87); + const expectedfee = bn(86); + const expectedmaxFee = bn(86); + const expectedminFee = bn(86); expect(fee.toNumber()).toEqual(expectedfee.toNumber()); - expect(feeFromGasUsed.toNumber()).toEqual(expectedfeeFromGasUsed.toNumber()); expect(maxFee.toNumber()).toEqual(expectedmaxFee.toNumber()); expect(minFee.toNumber()).toEqual(expectedminFee.toNumber()); }); it('should properly calculate the transaction fee (MINT TX)', () => { const transactionRawPayload = MOCK_TX_MINT_RAW_PAYLOAD; - const { gasCosts } = MOCK_CHAIN.consensusParameters; + const { + gasCosts, + txParams: { maxGasPerTx }, + } = MOCK_CHAIN.consensusParameters; const gasPriceFactor = 92; const gasPerByte = 4; - const { fee, feeFromGasUsed, maxFee, minFee } = calculateTransactionFee({ + const { fee, maxFee, minFee } = calculateTransactionFee({ + tip: bn(0), + gasPrice: bn(1), consensusParameters: { feeParams: { gasPriceFactor, gasPerByte, }, + maxGasPerTx: bn(maxGasPerTx), gasCosts, }, - gasUsed: bn(1), rawPayload: transactionRawPayload, }); expect(fee.toNumber()).toEqual(0); - expect(feeFromGasUsed.toNumber()).toEqual(0); expect(maxFee.toNumber()).toEqual(0); expect(minFee.toNumber()).toEqual(0); }); diff --git a/packages/account/src/providers/transaction-summary/calculate-transaction-fee.ts b/packages/account/src/providers/transaction-summary/calculate-transaction-fee.ts index b8a62d7579f..224367c319f 100644 --- a/packages/account/src/providers/transaction-summary/calculate-transaction-fee.ts +++ b/packages/account/src/providers/transaction-summary/calculate-transaction-fee.ts @@ -5,8 +5,8 @@ import { PolicyType, TransactionCoder, TransactionType } from '@fuel-ts/transact import { arrayify } from '@fuel-ts/utils'; import type { GqlConsensusParameters, GqlFeeParameters } from '../__generated__/operations'; -import { calculatePriceWithFactor } from '../utils'; import { + calculateGasFee, calculateMetadataGasForTxCreate, calculateMetadataGasForTxScript, getMaxGas, @@ -21,16 +21,21 @@ type FeeParams = }; export type CalculateTransactionFeeParams = { - gasUsed: BN; + gasPrice: BN; rawPayload: string; - consensusParameters: Pick & { feeParams: FeeParams }; + tip: BN; + consensusParameters: Pick & { + feeParams: FeeParams; + maxGasPerTx: BN; + }; }; export const calculateTransactionFee = (params: CalculateTransactionFeeParams) => { const { - gasUsed, + gasPrice, rawPayload, - consensusParameters: { gasCosts, feeParams }, + tip, + consensusParameters: { gasCosts, feeParams, maxGasPerTx }, } = params; const gasPerByte = bn(feeParams.gasPerByte); @@ -45,7 +50,6 @@ export const calculateTransactionFee = (params: CalculateTransactionFeeParams) = fee: bn(0), minFee: bn(0), maxFee: bn(0), - feeFromGasUsed: bn(0), }; } @@ -88,7 +92,6 @@ export const calculateTransactionFee = (params: CalculateTransactionFeeParams) = txBytesSize: transactionBytes.length, }); - const gasPrice = bn(policies.find((policy) => policy.type === PolicyType.GasPrice)?.data); const witnessLimit = policies.find((policy) => policy.type === PolicyType.WitnessLimit)?.data as | BN | undefined; @@ -101,17 +104,26 @@ export const calculateTransactionFee = (params: CalculateTransactionFeeParams) = witnessesLength, gasLimit, witnessLimit, + maxGasPerTx, + }); + + const minFee = calculateGasFee({ + gasPrice, + gas: minGas, + priceFactor: gasPriceFactor, + tip, }); - const feeFromGasUsed = calculatePriceWithFactor(gasUsed, gasPrice, gasPriceFactor); - const minFee = calculatePriceWithFactor(minGas, gasPrice, gasPriceFactor); - const maxFee = calculatePriceWithFactor(maxGas, gasPrice, gasPriceFactor); - const fee = minFee.add(feeFromGasUsed); + const maxFee = calculateGasFee({ + gasPrice, + gas: maxGas, + priceFactor: gasPriceFactor, + tip, + }); return { - fee, minFee, maxFee, - feeFromGasUsed, + fee: maxFee, }; }; diff --git a/packages/account/src/providers/transaction-summary/get-transaction-summary.ts b/packages/account/src/providers/transaction-summary/get-transaction-summary.ts index c863458ff52..3268c50d1a5 100644 --- a/packages/account/src/providers/transaction-summary/get-transaction-summary.ts +++ b/packages/account/src/providers/transaction-summary/get-transaction-summary.ts @@ -6,6 +6,7 @@ import { arrayify } from '@fuel-ts/utils'; import type { GqlGetTransactionsByOwnerQueryVariables, GqlPageInfo, + GqlReceiptFragmentFragment, } from '../__generated__/operations'; import type Provider from '../provider'; import type { TransactionRequest } from '../transaction-request'; @@ -43,12 +44,20 @@ export async function getTransactionSummary( 0 ); - const receipts = gqlTransaction.receipts?.map(processGqlReceipt) || []; + let txReceipts: GqlReceiptFragmentFragment[] = []; + + if (gqlTransaction?.status && 'receipts' in gqlTransaction.status) { + txReceipts = gqlTransaction.status.receipts; + } + + const receipts = txReceipts.map(processGqlReceipt); const { - consensusParameters: { gasPerByte, gasPriceFactor, maxInputs, gasCosts }, + consensusParameters: { gasPerByte, gasPriceFactor, maxInputs, gasCosts, maxGasPerTx }, } = provider.getChain(); + const gasPrice = await provider.getLatestGasPrice(); + const transactionInfo = assembleTransactionSummary({ id: gqlTransaction.id, receipts, @@ -60,6 +69,8 @@ export async function getTransactionSummary( abiMap, maxInputs, gasCosts, + maxGasPerTx, + gasPrice, }); return { @@ -82,12 +93,14 @@ export async function getTransactionSummaryFromRequest( const { receipts } = await provider.call(transactionRequest); - const { gasPerByte, gasPriceFactor, gasCosts } = provider.getGasConfig(); + const { gasPerByte, gasPriceFactor, gasCosts, maxGasPerTx } = provider.getGasConfig(); const maxInputs = provider.getChain().consensusParameters.maxInputs; const transaction = transactionRequest.toTransaction(); const transactionBytes = transactionRequest.toTransactionBytes(); + const gasPrice = await provider.getLatestGasPrice(); + const transactionSummary = assembleTransactionSummary({ receipts, transaction, @@ -97,6 +110,8 @@ export async function getTransactionSummaryFromRequest( gasPriceFactor, maxInputs, gasCosts, + maxGasPerTx, + gasPrice, }); return transactionSummary; @@ -124,17 +139,25 @@ export async function getTransactionsSummaries( const { edges, pageInfo } = transactionsByOwner; const { - consensusParameters: { gasPerByte, gasPriceFactor, maxInputs, gasCosts }, + consensusParameters: { gasPerByte, gasPriceFactor, maxInputs, gasCosts, maxGasPerTx }, } = provider.getChain(); + const gasPrice = await provider.getLatestGasPrice(); + const transactions = edges.map((edge) => { const { node: gqlTransaction } = edge; - const { id, rawPayload, receipts: gqlReceipts, status } = gqlTransaction; + const { id, rawPayload, status } = gqlTransaction; const [decodedTransaction] = new TransactionCoder().decode(arrayify(rawPayload), 0); - const receipts = gqlReceipts?.map(processGqlReceipt) || []; + let txReceipts: GqlReceiptFragmentFragment[] = []; + + if (gqlTransaction?.status && 'receipts' in gqlTransaction.status) { + txReceipts = gqlTransaction.status.receipts; + } + + const receipts = txReceipts.map(processGqlReceipt); const transactionSummary = assembleTransactionSummary({ id, @@ -147,6 +170,8 @@ export async function getTransactionsSummaries( gasPriceFactor, maxInputs, gasCosts, + maxGasPerTx, + gasPrice, }); const output: TransactionResult = { diff --git a/packages/account/src/providers/utils/gas.test.ts b/packages/account/src/providers/utils/gas.test.ts index 6049d574589..1856fee8b8f 100644 --- a/packages/account/src/providers/utils/gas.test.ts +++ b/packages/account/src/providers/utils/gas.test.ts @@ -21,7 +21,6 @@ import type { TransactionResultReceipt } from '../transaction-response'; import { calculateMetadataGasForTxCreate, calculateMetadataGasForTxScript, - calculatePriceWithFactor, gasUsedByInputs, getGasUsedFromReceipts, getMaxGas, @@ -206,6 +205,7 @@ describe('gas', () => { const witnessesLength = 128; const minGas = bn(567); const gasLimit = bn(10_000); + const maxGasPerTx = bn(MOCK_CHAIN.consensusParameters.txParams.maxGasPerTx); const expectedMaxGas = witnessLimit .sub(bn(witnessesLength)) @@ -219,6 +219,7 @@ describe('gas', () => { witnessesLength, minGas, gasLimit, + maxGasPerTx, }); expect(expectedMaxGas.eq(maxGas)).toBeTruthy(); @@ -229,6 +230,7 @@ describe('gas', () => { const witnessLimit = bn(200); const witnessesLength = 500; const minGas = bn(210); + const maxGasPerTx = bn(MOCK_CHAIN.consensusParameters.txParams.maxGasPerTx); const expectedMaxGas = minGas; @@ -237,6 +239,7 @@ describe('gas', () => { witnessLimit, witnessesLength, minGas, + maxGasPerTx, }); expect(expectedMaxGas.eq(maxGas)).toBeTruthy(); @@ -247,6 +250,7 @@ describe('gas', () => { const witnessLimit = undefined; const witnessesLength = 64; const minGas = bn(350); + const maxGasPerTx = bn(MOCK_CHAIN.consensusParameters.txParams.maxGasPerTx); const expectedMaxGas = minGas; @@ -255,6 +259,7 @@ describe('gas', () => { witnessLimit, witnessesLength, minGas, + maxGasPerTx, }); expect(expectedMaxGas.eq(maxGas)).toBeTruthy(); @@ -301,28 +306,6 @@ describe('gas', () => { }); }); - describe('calculatePriceWithFactor', () => { - it('should correctly calculate the price with factor', () => { - const gasUsed = new BN(10); - const gasPrice = new BN(2); - const priceFactor = new BN(5); - - const result = calculatePriceWithFactor(gasUsed, gasPrice, priceFactor); - - expect(result.toNumber()).toEqual(4); // ceil(10 / 5) * 2 = 4 - }); - - it('should correctly round up the result', () => { - const gasUsed = new BN(11); - const gasPrice = new BN(2); - const priceFactor = new BN(5); - - const result = calculatePriceWithFactor(gasUsed, gasPrice, priceFactor); - - expect(result.toNumber()).toEqual(5); // ceil(11 * 2) / 2 = 5 - }); - }); - describe('getGasUsedFromReceipts', () => { it('should return correct total gas used from ScriptResult receipts', () => { const receipts: Array = [ diff --git a/packages/account/src/providers/utils/gas.ts b/packages/account/src/providers/utils/gas.ts index f2be1a6064f..c0c9484af92 100644 --- a/packages/account/src/providers/utils/gas.ts +++ b/packages/account/src/providers/utils/gas.ts @@ -1,5 +1,5 @@ -import type { BN, BNInput } from '@fuel-ts/math'; import { bn } from '@fuel-ts/math'; +import type { BN, BNInput } from '@fuel-ts/math'; import { ReceiptType, type Input } from '@fuel-ts/transactions'; import { arrayify } from '@fuel-ts/utils'; @@ -10,10 +10,6 @@ import type { TransactionResultScriptResultReceipt, } from '../transaction-response'; -/** @hidden */ -export const calculatePriceWithFactor = (gas: BN, gasPrice: BN, priceFactor: BN): BN => - bn(Math.ceil(gas.mul(gasPrice).toNumber() / priceFactor.toNumber())); - /** @hidden */ export const getGasUsedFromReceipts = (receipts: Array): BN => { const scriptResult = receipts.filter( @@ -43,20 +39,36 @@ export function gasUsedByInputs( gasCosts: GqlGasCosts ) { const witnessCache: Array = []; - const totalGas = inputs.reduce((total, input) => { + + const chargeableInputs = inputs.filter((input) => { + const isCoinOrMessage = 'owner' in input || 'sender' in input; + if (isCoinOrMessage) { + if ('predicate' in input && input.predicate && input.predicate !== '0x') { + return true; + } + + if (!witnessCache.includes(input.witnessIndex)) { + // should charge only once for each witness + witnessCache.push(input.witnessIndex); + return true; + } + } + return false; + }); + + const vmInitializationCost = resolveGasDependentCosts(txBytesSize, gasCosts.vmInitialization); + + const totalGas = chargeableInputs.reduce((total, input) => { if ('predicate' in input && input.predicate && input.predicate !== '0x') { return total.add( - resolveGasDependentCosts(txBytesSize, gasCosts.vmInitialization) + vmInitializationCost .add(resolveGasDependentCosts(arrayify(input.predicate).length, gasCosts.contractRoot)) .add(bn(input.predicateGasUsed)) ); } - if ('witnessIndex' in input && !witnessCache.includes(input.witnessIndex)) { - witnessCache.push(input.witnessIndex); - return total.add(gasCosts.ecr1); - } - return total; - }, bn()); + + return total.add(gasCosts.ecr1); + }, bn(0)); // Never allow gas to exceed MAX_U64 return totalGas; } @@ -87,10 +99,18 @@ export interface IGetMaxGasParams { gasPerByte: BN; minGas: BN; gasLimit?: BN; + maxGasPerTx: BN; } export function getMaxGas(params: IGetMaxGasParams) { - const { gasPerByte, witnessesLength, witnessLimit, minGas, gasLimit = bn(0) } = params; + const { + gasPerByte, + witnessesLength, + witnessLimit, + minGas, + gasLimit = bn(0), + maxGasPerTx, + } = params; let remainingAllowedWitnessGas = bn(0); @@ -98,7 +118,9 @@ export function getMaxGas(params: IGetMaxGasParams) { remainingAllowedWitnessGas = bn(witnessLimit).sub(witnessesLength).mul(gasPerByte); } - return remainingAllowedWitnessGas.add(minGas).add(gasLimit); + const maxGas = remainingAllowedWitnessGas.add(minGas).add(gasLimit); + + return maxGas.gte(maxGasPerTx) ? maxGasPerTx : maxGas; } export function calculateMetadataGasForTxCreate({ @@ -131,3 +153,15 @@ export function calculateMetadataGasForTxScript({ }) { return resolveGasDependentCosts(txBytesSize, gasCosts.s256); } + +export interface CalculateGasFeeParams { + tip: BN; + gas: BN; + gasPrice: BN; + priceFactor: BN; +} + +export const calculateGasFee = (params: CalculateGasFeeParams) => { + const { gas, gasPrice, priceFactor, tip } = params; + return gas.mul(gasPrice).div(priceFactor).add(tip); +}; diff --git a/packages/account/src/providers/utils/receipts.test.ts b/packages/account/src/providers/utils/receipts.test.ts index 69eb697bc65..cc9b6b86c0f 100644 --- a/packages/account/src/providers/utils/receipts.test.ts +++ b/packages/account/src/providers/utils/receipts.test.ts @@ -37,8 +37,8 @@ describe('assembleReceiptByType', () => { expect(receipt.type).toBe(ReceiptType.Call); expect(receipt.assetId).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.assetId); - expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); - expect(receipt.to).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.to?.id); + expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); + expect(receipt.to).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.to); expect(receipt.amount).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.amount)); expect(receipt.gas).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.gas)); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); @@ -54,7 +54,7 @@ describe('assembleReceiptByType', () => { }) as ReceiptReturn; expect(receipt.type).toBe(ReceiptType.Return); - expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); + expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); expect(receipt.pc).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.pc)); expect(receipt.val).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.val)); @@ -67,7 +67,7 @@ describe('assembleReceiptByType', () => { }) as ReceiptReturnData; expect(receipt.type).toBe(ReceiptType.ReturnData); - expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); + expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); expect(receipt.digest).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.digest); expect(receipt.len).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.len)); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); @@ -82,7 +82,7 @@ describe('assembleReceiptByType', () => { }) as ReceiptPanic; expect(receipt.type).toBe(ReceiptType.Panic); - expect(receipt.id).toEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); + expect(receipt.id).toEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); expect(receipt.contractId).toEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); expect(receipt.pc).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.pc)); @@ -96,7 +96,7 @@ describe('assembleReceiptByType', () => { }) as ReceiptRevert; expect(receipt.type).toBe(ReceiptType.Revert); - expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); + expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); expect(receipt.val).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.ra)); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); expect(receipt.pc).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.pc)); @@ -109,7 +109,7 @@ describe('assembleReceiptByType', () => { }) as ReceiptLog; expect(receipt.type).toBe(ReceiptType.Log); - expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); + expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); expect(receipt.pc).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.pc)); expect(receipt.val0).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.ra)); @@ -125,7 +125,7 @@ describe('assembleReceiptByType', () => { }) as ReceiptLogData; expect(receipt.type).toBe(ReceiptType.LogData); - expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); + expect(receipt.id).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); expect(receipt.digest).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.digest); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); expect(receipt.pc).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.pc)); @@ -142,8 +142,8 @@ describe('assembleReceiptByType', () => { }) as ReceiptTransfer; expect(receipt.type).toBe(ReceiptType.Transfer); - expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); - expect(receipt.to).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.to?.id); + expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); + expect(receipt.to).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.to); expect(receipt.assetId).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.assetId); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); expect(receipt.pc).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.pc)); @@ -157,7 +157,7 @@ describe('assembleReceiptByType', () => { }) as ReceiptTransferOut; expect(receipt.type).toBe(ReceiptType.TransferOut); - expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.contract?.id); + expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.contractId); expect(receipt.to).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.toAddress); expect(receipt.assetId).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.assetId); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.is)); @@ -172,8 +172,8 @@ describe('assembleReceiptByType', () => { }) as ReceiptTransferOut; expect(receipt.type).toBe(ReceiptType.TransferOut); - expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contract?.id); - expect(receipt.to).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.to?.id); + expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.contractId); + expect(receipt.to).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.to); expect(receipt.assetId).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT.assetId); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.is)); expect(receipt.pc).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT.pc)); @@ -187,7 +187,7 @@ describe('assembleReceiptByType', () => { }) as ReceiptTransferOut; expect(receipt.type).toBe(ReceiptType.TransferOut); - expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.contract?.id); + expect(receipt.from).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.contractId); expect(receipt.to).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.toAddress); expect(receipt.assetId).toStrictEqual(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.assetId); expect(receipt.is).toStrictEqual(new BN(MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS.is)); @@ -238,7 +238,7 @@ describe('assembleReceiptByType', () => { }); it('should return a ReceiptMint when GqlReceiptType.Mint is provided', () => { - const contractId = MOCK_GQL_RECEIPT_FRAGMENT.contract?.id || ''; + const contractId = MOCK_GQL_RECEIPT_FRAGMENT.id || ''; const subId = MOCK_GQL_RECEIPT_FRAGMENT.subId || ''; const assetId = ReceiptBurnCoder.getAssetId(contractId, subId); @@ -257,7 +257,7 @@ describe('assembleReceiptByType', () => { }); it('should return a ReceiptBurn when GqlReceiptType.Burn is provided', () => { - const contractId = MOCK_GQL_RECEIPT_FRAGMENT.contract?.id || ''; + const contractId = MOCK_GQL_RECEIPT_FRAGMENT.id || ''; const subId = MOCK_GQL_RECEIPT_FRAGMENT.subId || ''; const assetId = ReceiptBurnCoder.getAssetId(contractId, subId); diff --git a/packages/account/src/providers/utils/receipts.ts b/packages/account/src/providers/utils/receipts.ts index ad73bffb2be..a9691718bd5 100644 --- a/packages/account/src/providers/utils/receipts.ts +++ b/packages/account/src/providers/utils/receipts.ts @@ -73,8 +73,8 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.Call: { const callReceipt: ReceiptCall = { type: ReceiptType.Call, - from: hexOrZero(receipt.contract?.id), - to: hexOrZero(receipt?.to?.id), + from: hexOrZero(receipt.id || receipt.contractId), + to: hexOrZero(receipt?.to), amount: bn(receipt.amount), assetId: hexOrZero(receipt.assetId), gas: bn(receipt.gas), @@ -90,7 +90,7 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.Return: { const returnReceipt: ReceiptReturn = { type: ReceiptType.Return, - id: hexOrZero(receipt.contract?.id), + id: hexOrZero(receipt.id || receipt.contractId), val: bn(receipt.val), pc: bn(receipt.pc), is: bn(receipt.is), @@ -102,7 +102,7 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.ReturnData: { const returnDataReceipt: ReceiptReturnData = { type: ReceiptType.ReturnData, - id: hexOrZero(receipt.contract?.id), + id: hexOrZero(receipt.id || receipt.contractId), ptr: bn(receipt.ptr), len: bn(receipt.len), digest: hexOrZero(receipt.digest), @@ -116,7 +116,7 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.Panic: { const panicReceipt: ReceiptPanic = { type: ReceiptType.Panic, - id: hexOrZero(receipt.contract?.id), + id: hexOrZero(receipt.id), reason: bn(receipt.reason), pc: bn(receipt.pc), is: bn(receipt.is), @@ -129,7 +129,7 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.Revert: { const revertReceipt: ReceiptRevert = { type: ReceiptType.Revert, - id: hexOrZero(receipt.contract?.id), + id: hexOrZero(receipt.id || receipt.contractId), val: bn(receipt.ra), pc: bn(receipt.pc), is: bn(receipt.is), @@ -140,7 +140,7 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.Log: { const logReceipt: ReceiptLog = { type: ReceiptType.Log, - id: hexOrZero(receipt.contract?.id), + id: hexOrZero(receipt.id || receipt.contractId), val0: bn(receipt.ra), val1: bn(receipt.rb), val2: bn(receipt.rc), @@ -155,7 +155,7 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.LogData: { const logDataReceipt: ReceiptLogData = { type: ReceiptType.LogData, - id: hexOrZero(receipt.contract?.id), + id: hexOrZero(receipt.id || receipt.contractId), val0: bn(receipt.ra), val1: bn(receipt.rb), ptr: bn(receipt.ptr), @@ -170,8 +170,8 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.Transfer: { const transferReceipt: ReceiptTransfer = { type: ReceiptType.Transfer, - from: hexOrZero(receipt.contract?.id), - to: hexOrZero(receipt.toAddress || receipt?.to?.id), + from: hexOrZero(receipt.id || receipt.contractId), + to: hexOrZero(receipt.toAddress || receipt?.to), amount: bn(receipt.amount), assetId: hexOrZero(receipt.assetId), pc: bn(receipt.pc), @@ -184,8 +184,8 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { case GqlReceiptType.TransferOut: { const transferOutReceipt: ReceiptTransferOut = { type: ReceiptType.TransferOut, - from: hexOrZero(receipt.contract?.id), - to: hexOrZero(receipt.toAddress || receipt.to?.id), + from: hexOrZero(receipt.id || receipt.contractId), + to: hexOrZero(receipt.toAddress || receipt.to), amount: bn(receipt.amount), assetId: hexOrZero(receipt.assetId), pc: bn(receipt.pc), @@ -235,7 +235,7 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { } case GqlReceiptType.Mint: { - const contractId = hexOrZero(receipt.contract?.id); + const contractId = hexOrZero(receipt.id || receipt.contractId); const subId = hexOrZero(receipt.subId); const assetId = ReceiptMintCoder.getAssetId(contractId, subId); @@ -253,7 +253,7 @@ export function assembleReceiptByType(receipt: GqlReceiptFragmentFragment) { } case GqlReceiptType.Burn: { - const contractId = hexOrZero(receipt.contract?.id); + const contractId = hexOrZero(receipt.id || receipt.contractId); const subId = hexOrZero(receipt.subId); const assetId = ReceiptBurnCoder.getAssetId(contractId, subId); diff --git a/packages/account/src/test-utils/launchNode.ts b/packages/account/src/test-utils/launchNode.ts index 2cb1fe4e8cd..732c81d3343 100644 --- a/packages/account/src/test-utils/launchNode.ts +++ b/packages/account/src/test-utils/launchNode.ts @@ -190,7 +190,7 @@ export const launchNode = async ({ ['--ip', ipToUse], ['--port', portToUse], useInMemoryDb ? ['--db-type', 'in-memory'] : ['--db-path', tempDirPath], - ['--min-gas-price', '0'], + ['--min-gas-price', '1'], poaInstant ? ['--poa-instant', 'true'] : [], ['--consensus-key', consensusKey], ['--chain', chainConfigPathToUse as string], @@ -284,7 +284,7 @@ export const launchNodeAndGetWallets = async ({ } = {}): LaunchNodeAndGetWalletsResult => { const { cleanup: closeNode, ip, port } = await launchNode(launchNodeOptions || {}); - const provider = await Provider.create(`http://${ip}:${port}/graphql`); + const provider = await Provider.create(`http://${ip}:${port}/v1/graphql`); const wallets = await generateWallets(walletCount, provider); const cleanup = () => { diff --git a/packages/account/src/test-utils/seedTestWallet.ts b/packages/account/src/test-utils/seedTestWallet.ts index 0561156bcbc..409eb7aa7b7 100644 --- a/packages/account/src/test-utils/seedTestWallet.ts +++ b/packages/account/src/test-utils/seedTestWallet.ts @@ -11,21 +11,21 @@ export const seedTestWallet = async (wallet: Account, quantities: CoinQuantityLi wallet.provider ); + // Create transaction + const request = new ScriptTransactionRequest(); + // Connect to the same Provider as wallet - const resources = await genesisWallet.getResourcesToSpend(quantities); + quantities.forEach((quantity) => { + const { amount, assetId } = coinQuantityfy(quantity); + request.addCoinOutput(wallet.address, amount, assetId); + }); - const { minGasPrice } = genesisWallet.provider.getGasConfig(); + const txCost = await genesisWallet.provider.getTransactionCost(request); - // Create transaction - const request = new ScriptTransactionRequest({ - gasLimit: 10000, - gasPrice: minGasPrice, - }); + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - request.addResources(resources); + await genesisWallet.fund(request, txCost); - quantities - .map(coinQuantityfy) - .forEach(({ amount, assetId }) => request.addCoinOutput(wallet.address, amount, assetId)); await genesisWallet.sendTransaction(request, { awaitExecution: true }); }; diff --git a/packages/account/src/wallet/base-wallet-unlocked.ts b/packages/account/src/wallet/base-wallet-unlocked.ts index 9006335d5ee..0ee820bf4a9 100644 --- a/packages/account/src/wallet/base-wallet-unlocked.ts +++ b/packages/account/src/wallet/base-wallet-unlocked.ts @@ -108,7 +108,7 @@ export class BaseWalletUnlocked extends Account { */ async sendTransaction( transactionRequestLike: TransactionRequestLike, - { estimateTxDependencies = true, awaitExecution }: ProviderSendTxParams = {} + { estimateTxDependencies = false, awaitExecution }: ProviderSendTxParams = {} ): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); if (estimateTxDependencies) { diff --git a/packages/account/src/wallet/wallet.test.ts b/packages/account/src/wallet/wallet.test.ts index 5f6d4a11984..d1374d16c69 100644 --- a/packages/account/src/wallet/wallet.test.ts +++ b/packages/account/src/wallet/wallet.test.ts @@ -1,6 +1,5 @@ import { BaseAssetId } from '@fuel-ts/address/configs'; import { safeExec } from '@fuel-ts/errors/test-utils'; -import type { BN } from '@fuel-ts/math'; import { bn } from '@fuel-ts/math'; import { FUEL_NETWORK_URL } from '../configs'; @@ -17,11 +16,9 @@ import { WalletLocked, WalletUnlocked } from './wallets'; describe('Wallet', () => { let wallet: WalletUnlocked; let provider: Provider; - let gasPrice: BN; beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); wallet = Wallet.generate({ provider }); - gasPrice = provider.getGasConfig().minGasPrice; }); describe('WalletLocked.constructor', () => { @@ -211,7 +208,7 @@ describe('Wallet', () => { externalWalletReceiver.address, bn(1_000_000), BaseAssetId, - { gasPrice, gasLimit: 10_000 } + { gasLimit: 10_000 } ); await response.wait(); diff --git a/packages/account/test/auto-retry-fetch.test.ts b/packages/account/test/auto-retry-fetch.test.ts index 157107e6f69..5e1f24a9db5 100644 --- a/packages/account/test/auto-retry-fetch.test.ts +++ b/packages/account/test/auto-retry-fetch.test.ts @@ -1,10 +1,8 @@ +import { FUEL_NETWORK_URL } from '../src/configs'; import Provider from '../src/providers/provider'; import * as autoRetryFetchMod from '../src/providers/utils/auto-retry-fetch'; import type { RetryOptions } from '../src/providers/utils/auto-retry-fetch'; -// TODO: Figure out a way to import this constant from `@fuel-ts/account/configs` -const FUEL_NETWORK_URL = 'http://127.0.0.1:4000/graphql'; - /** * @group node * TODO: add browser group as well (https://github.com/FuelLabs/fuels-ts/pull/1654#discussion_r1456501593) diff --git a/packages/account/test/fixtures/chain.ts b/packages/account/test/fixtures/chain.ts index da6cf63447b..e191b600caa 100644 --- a/packages/account/test/fixtures/chain.ts +++ b/packages/account/test/fixtures/chain.ts @@ -52,7 +52,6 @@ export const MOCK_CHAIN: GqlChainInfoFragmentFragment = { cb: '1', cfei: '1', cfsi: '1', - croo: '16', div: '1', divi: '1', ecr1: '3000', @@ -139,6 +138,11 @@ export const MOCK_CHAIN: GqlChainInfoFragmentFragment = { base: '15', unitsPerGas: '103', }, + croo: { + __typename: 'LightOperation', + base: '15', + unitsPerGas: '103', + }, csiz: { __typename: 'LightOperation', base: '17', @@ -235,7 +239,8 @@ export const MOCK_CHAIN: GqlChainInfoFragmentFragment = { latestBlock: { __typename: 'Block', id: '0xb9e55ced368c8d8f1aa487d33e97043e5891406792ea5d61f7807d0441d34722', - header: { __typename: 'Header', height: '234', time: '4611686020122537935' }, + height: '234', + header: { __typename: 'Header', time: '4611686020122537935' }, transactions: [ { __typename: 'Transaction', diff --git a/packages/account/test/fixtures/inputs-and-outputs.ts b/packages/account/test/fixtures/inputs-and-outputs.ts index f5aba069987..9c9684049b7 100644 --- a/packages/account/test/fixtures/inputs-and-outputs.ts +++ b/packages/account/test/fixtures/inputs-and-outputs.ts @@ -26,7 +26,6 @@ export const MOCK_COIN_INPUT: InputCoin = { txIndex: 0, }, witnessIndex: 0, - maturity: 0, predicateGasUsed: bn(0), predicateLength: 0, predicateDataLength: 0, @@ -58,7 +57,6 @@ export const MOCK_REQUEST_COIN_INPUT: CoinTransactionRequestInput = { owner: getRandomB256(), txPointer: '0x00000000000000000000000000000000', witnessIndex: 0, - maturity: 0, }; export const MOCK_REQUEST_PREDICATE_INPUT: CoinTransactionRequestInput = { @@ -69,7 +67,6 @@ export const MOCK_REQUEST_PREDICATE_INPUT: CoinTransactionRequestInput = { owner: getRandomB256(), txPointer: '0x00000000000000000000000000000000', witnessIndex: 0, - maturity: 0, predicate: '0x862512a2363db2b3a375c0d4bbbd27172180d89f23f2e259bac850ab02619301', predicateGasUsed: bn(0), }; diff --git a/packages/account/test/fixtures/nodeInfo.ts b/packages/account/test/fixtures/nodeInfo.ts index ab98e21b598..08b7e22341a 100644 --- a/packages/account/test/fixtures/nodeInfo.ts +++ b/packages/account/test/fixtures/nodeInfo.ts @@ -8,5 +8,4 @@ export const MOCK_NODE_INFO: GqlNodeInfoFragmentFragment = { maxTx: '4064', maxDepth: '10', nodeVersion: '0.22.0', - peers: [], }; diff --git a/packages/account/test/fixtures/receipts.ts b/packages/account/test/fixtures/receipts.ts index 54383494299..eeae382fb30 100644 --- a/packages/account/test/fixtures/receipts.ts +++ b/packages/account/test/fixtures/receipts.ts @@ -6,19 +6,14 @@ export const MOCK_GQL_RECEIPT_FRAGMENT: GqlReceiptFragmentFragment = { pc: '15488', is: '15488', __typename: 'Receipt', - to: { - __typename: 'Contract', - id: '0xfc69a2f25c26312fbecc7fce531eca80a2d315482c03fbc00d36b5cf065a0ac3', - }, + to: '0xfc69a2f25c26312fbecc7fce531eca80a2d315482c03fbc00d36b5cf065a0ac3', amount: '100', assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', gas: '499999489', param1: '1208122719', param2: '12568', - contract: { - __typename: 'Contract', - id: '0xfc69a2f25c26312fbecc7fce531eca80a2d315482c03fbc00d36b5cf065a0ac3', - }, + id: '0xfc69a2f25c26312fbecc7fce531eca80a2d315482c03fbc00d36b5cf065a0ac3', + contractId: '0xfc69a2f25c26312fbecc7fce531eca80a2d315482c03fbc00d36b5cf065a0ac3', val: '1', ptr: '13296', digest: '0x5df9236f59b3efbbd5737ae43edaf76587e2820cff27a6d9f1cd7750fa592028', @@ -35,7 +30,6 @@ export const MOCK_GQL_RECEIPT_FRAGMENT: GqlReceiptFragmentFragment = { recipient: '0x00000000000000000000000047ba61eec8e5e65247d717ff236f504cf3b0a263', nonce: '0x343628340232f09d8183a89c22b4edf6b615d8edd30b72945d04d6829ba86b85', subId: '0x0000000000000000000000000000000000000000000000000000000000000000', - contractId: '0x45f7524a92f661c0f2e4d7b8def42e46b8e2f478a3c51916540e32d8f60a2f53', }; export const MOCK_GQL_RECEIPT_FRAGMENT_TO_ADDRESS: GqlReceiptFragmentFragment = { diff --git a/packages/account/test/fixtures/transaction-request.ts b/packages/account/test/fixtures/transaction-request.ts index e7b3a7a0c68..9e9e7952532 100644 --- a/packages/account/test/fixtures/transaction-request.ts +++ b/packages/account/test/fixtures/transaction-request.ts @@ -4,7 +4,7 @@ export const SCRIPT_TX_REQUEST = new ScriptTransactionRequest({ gasLimit: 10_000, script: '0x24400000', scriptData: Uint8Array.from([]), - gasPrice: 10, + tip: 10, maxFee: 90000, maturity: 0, witnessLimit: 3000, @@ -15,7 +15,6 @@ export const SCRIPT_TX_REQUEST = new ScriptTransactionRequest({ assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', amount: '0x989680', owner: '0xf1e92c42b90934aa6372e30bc568a326f6e66a1a0288595e6e3fbd392a4f3e6e', - maturity: 0, txPointer: '0x00000000000000000000000000000000', witnessIndex: 0, predicate: '0x', diff --git a/packages/account/test/fixtures/transaction-summary.ts b/packages/account/test/fixtures/transaction-summary.ts index cd62edd99ed..b31ad6f412e 100644 --- a/packages/account/test/fixtures/transaction-summary.ts +++ b/packages/account/test/fixtures/transaction-summary.ts @@ -30,7 +30,6 @@ import type { export const MOCK_INPUT_COIN: InputCoin = { amount: bn(4999989993), assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', - maturity: 0, owner: '0x3e7ddda4d0d3f8307ae5f1aed87623992c1c4decefec684936960775181b2302', predicateGasUsed: bn(0), predicate: '0x', @@ -290,6 +289,7 @@ export const MOCK_SUCCESS_STATUS: SuccessStatus = { __typename: 'Block', id: '0x123', }, + receipts: [], }; export const MOCK_FAILURE_STATUS: FailureStatus = { @@ -301,6 +301,7 @@ export const MOCK_FAILURE_STATUS: FailureStatus = { }, reason: 'reason', time: '4611686020122012535', + receipts: [], }; export const MOCK_SUBMITTED_STATUS: SubmittedStatus = { diff --git a/packages/account/test/fixtures/wallet-unlocked.ts b/packages/account/test/fixtures/wallet-unlocked.ts index 405199f04f7..728d84e1390 100644 --- a/packages/account/test/fixtures/wallet-unlocked.ts +++ b/packages/account/test/fixtures/wallet-unlocked.ts @@ -4,7 +4,7 @@ export const SCRIPT_TX_REQUEST = new ScriptTransactionRequest({ gasLimit: 5_000, script: '0x', scriptData: Uint8Array.from([]), - gasPrice: 5, + tip: 5, maxFee: 20_000, maturity: 0, witnessLimit: 5000, @@ -15,7 +15,6 @@ export const SCRIPT_TX_REQUEST = new ScriptTransactionRequest({ assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', amount: '0x989680', owner: '0xf1e92c42b90934aa6372e30bc568a326f6e66a1a0288595e6e3fbd392a4f3e6e', - maturity: 0, txPointer: '0x00000000000000000000000000000000', witnessIndex: 0, predicate: '0x', @@ -40,4 +39,4 @@ export const PUBLIC_KEY = export const ADDRESS = '0xf1e92c42b90934aa6372e30bc568a326f6e66a1a0288595e6e3fbd392a4f3e6e'; export const HASHED_TX = '0x48ee795d94ea9562a3dbb9979cb44bb3dfd341eb755c378b14a3cd6886189980'; export const SIGNED_TX = - '0x4b68db1c036e28b0ae2df25410880abaac46d5d6018b5594efa1b3854f81d937b58a609e43ac3606bfba54ca9ac03f7b076bd745b4b58f885d96a68c3006db15'; + '0xb5a9cc9834ef8341203ffef084afe58c257418b267e755ca2a85d402145f1b68205a6f91c5414182966c2aebc235d59059becf75aee05016cffc8e72f0e767f3'; diff --git a/packages/account/test/fuel-wallet-connector.test.ts b/packages/account/test/fuel-wallet-connector.test.ts index 9e808da8c6d..e6b676b1c2d 100644 --- a/packages/account/test/fuel-wallet-connector.test.ts +++ b/packages/account/test/fuel-wallet-connector.test.ts @@ -351,7 +351,7 @@ describe('Fuel Connector', () => { expect(wallet.provider.url).toEqual(network.url); const receiver = Wallet.fromAddress(Address.fromRandom(), provider); const response = await wallet.transfer(receiver.address, bn(1000), BaseAssetId, { - gasPrice: bn(1), + tip: bn(1), gasLimit: bn(100_000), }); const { status } = await response.waitForResult(); diff --git a/packages/contract/src/contract-factory.ts b/packages/contract/src/contract-factory.ts index 83ed38d744c..74f11428644 100644 --- a/packages/contract/src/contract-factory.ts +++ b/packages/contract/src/contract-factory.ts @@ -113,7 +113,6 @@ export default class ContractFactory { const stateRoot = options.stateRoot || getContractStorageRoot(options.storageSlots); const contractId = getContractId(this.bytecode, options.salt, stateRoot); const transactionRequest = new CreateTransactionRequest({ - gasPrice: 0, bytecodeWitnessIndex: 0, witnesses: [this.bytecode], ...options, @@ -145,13 +144,11 @@ export default class ContractFactory { const { contractId, transactionRequest } = this.createTransactionRequest(deployContractOptions); - const { requiredQuantities, maxFee } = - await this.account.provider.getTransactionCost(transactionRequest); + const txCost = await this.account.provider.getTransactionCost(transactionRequest); - transactionRequest.gasPrice = this.account.provider.getGasConfig().minGasPrice; - transactionRequest.maxFee = this.account.provider.getGasConfig().maxGasPerTx; + transactionRequest.maxFee = txCost.maxFee; - await this.account.fund(transactionRequest, requiredQuantities, maxFee); + await this.account.fund(transactionRequest, txCost); await this.account.sendTransaction(transactionRequest, { awaitExecution: true, }); diff --git a/packages/forc/VERSION b/packages/forc/VERSION index 72c9da1faf2..1e0c609c978 100644 --- a/packages/forc/VERSION +++ b/packages/forc/VERSION @@ -1 +1 @@ -0.49.3 +0.51.1 diff --git a/packages/fuel-core/VERSION b/packages/fuel-core/VERSION index a723ece79bc..ca222b7cf39 100644 --- a/packages/fuel-core/VERSION +++ b/packages/fuel-core/VERSION @@ -1 +1 @@ -0.22.1 +0.23.0 diff --git a/packages/fuel-gauge/src/advanced-logging.test.ts b/packages/fuel-gauge/src/advanced-logging.test.ts index e701c7cc061..80a777ad86c 100644 --- a/packages/fuel-gauge/src/advanced-logging.test.ts +++ b/packages/fuel-gauge/src/advanced-logging.test.ts @@ -1,6 +1,6 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; import type { FuelError } from '@fuel-ts/errors'; -import type { BN, Contract, Provider, WalletUnlocked } from 'fuels'; +import type { Contract, Provider, WalletUnlocked } from 'fuels'; import { Script, bn } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; @@ -15,7 +15,6 @@ let advancedLogContract: Contract; let otherAdvancedLogContract: Contract; let advancedLogId: string; let otherLogId: string; -let minGasPrice: BN; beforeAll(async () => { advancedLogContract = await setupContract(); @@ -23,7 +22,6 @@ beforeAll(async () => { provider = advancedLogContract.provider; advancedLogId = advancedLogContract.id.toB256(); otherLogId = otherAdvancedLogContract.id.toB256(); - minGasPrice = provider.getGasConfig().minGasPrice; }); /** @@ -190,20 +188,16 @@ describe('Advanced Logging', () => { ]) .getTransactionRequest(); - const { maxFee, gasUsed, requiredQuantities } = await provider.getTransactionCost( - request, - [], - { - resourcesOwner: wallet, - } - ); + const txCost = await provider.getTransactionCost(request, { + resourcesOwner: wallet, + }); - request.gasLimit = gasUsed; - request.gasPrice = minGasPrice; + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - await wallet.fund(request, requiredQuantities, maxFee); + await wallet.fund(request, txCost); - const tx = await wallet.sendTransaction(request); + const tx = await wallet.sendTransaction(request, { estimateTxDependencies: false }); const { logs } = await tx.waitForResult(); @@ -258,18 +252,14 @@ describe('Advanced Logging', () => { .addContracts([advancedLogContract, otherAdvancedLogContract]) .getTransactionRequest(); - const { maxFee, gasUsed, requiredQuantities } = await provider.getTransactionCost( - request, - [], - { - resourcesOwner: wallet, - } - ); + const txCost = await provider.getTransactionCost(request, { + resourcesOwner: wallet, + }); - request.gasLimit = gasUsed; - request.gasPrice = minGasPrice; + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - await wallet.fund(request, requiredQuantities, maxFee); + await wallet.fund(request, txCost); const tx = await wallet.sendTransaction(request); diff --git a/packages/fuel-gauge/src/auth-testing.test.ts b/packages/fuel-gauge/src/auth-testing.test.ts index df377527dae..9af776d505f 100644 --- a/packages/fuel-gauge/src/auth-testing.test.ts +++ b/packages/fuel-gauge/src/auth-testing.test.ts @@ -1,12 +1,11 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; -import type { BN, Contract, WalletUnlocked } from 'fuels'; +import type { Contract, WalletUnlocked } from 'fuels'; import { ContractFactory, BaseAssetId, Provider, getRandomB256, FUEL_NETWORK_URL } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; let contractInstance: Contract; let wallet: WalletUnlocked; -let gasPrice: BN; /** * @group node @@ -14,7 +13,6 @@ let gasPrice: BN; describe('Auth Testing', () => { beforeAll(async () => { const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); wallet = await generateTestWallet(provider, [[1_000_000, BaseAssetId]]); const { binHexlified, abiContents } = getFuelGaugeForcProject( @@ -22,7 +20,7 @@ describe('Auth Testing', () => { ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - contractInstance = await factory.deployContract({ gasPrice }); + contractInstance = await factory.deployContract(); }); it('can get is_caller_external', async () => { diff --git a/packages/fuel-gauge/src/await-execution.test.ts b/packages/fuel-gauge/src/await-execution.test.ts index 60743e48c89..e573998f7e4 100644 --- a/packages/fuel-gauge/src/await-execution.test.ts +++ b/packages/fuel-gauge/src/await-execution.test.ts @@ -16,7 +16,7 @@ describe('await-execution', () => { const { cleanup, ip, port } = await launchNode({ args: ['--poa-instant', 'false', '--poa-interval-period', '400ms'], }); - const nodeProvider = await Provider.create(`http://${ip}:${port}/graphql`); + const nodeProvider = await Provider.create(`http://${ip}:${port}/v1/graphql`); const genesisWallet = new WalletUnlocked( process.env.GENESIS_SECRET || randomBytes(32), @@ -26,7 +26,6 @@ describe('await-execution', () => { const destination = Wallet.generate({ provider: nodeProvider }); const transfer = await genesisWallet.createTransfer(destination.address, 100, BaseAssetId, { - gasPrice: nodeProvider.getGasConfig().minGasPrice, gasLimit: 10_000, }); @@ -58,7 +57,6 @@ describe('await-execution', () => { 100, BaseAssetId, { - gasPrice: provider.getGasConfig().minGasPrice, gasLimit: 10_000, } // { awaitExecution: true } @@ -84,7 +82,6 @@ describe('await-execution', () => { destination.address, 100, { - gasPrice: provider.getGasConfig().minGasPrice, gasLimit: 10_000, } // { awaitExecution: true } diff --git a/packages/fuel-gauge/src/bytes.test.ts b/packages/fuel-gauge/src/bytes.test.ts index ce9e75c37e5..d7d06616b88 100644 --- a/packages/fuel-gauge/src/bytes.test.ts +++ b/packages/fuel-gauge/src/bytes.test.ts @@ -34,12 +34,6 @@ const setup = async (balance = 500_000) => { * @group node */ describe('Bytes Tests', () => { - let gasPrice: BN; - beforeAll(async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); - }); - it('should test bytes output', async () => { const INPUT = 10; @@ -101,7 +95,6 @@ describe('Bytes Tests', () => { // setup predicate const setupTx = await wallet.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await setupTx.waitForResult(); @@ -110,7 +103,6 @@ describe('Bytes Tests', () => { const initialReceiverBalance = await receiver.getBalance(); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await tx.waitForResult(); diff --git a/packages/fuel-gauge/src/configurable-contract.test.ts b/packages/fuel-gauge/src/configurable-contract.test.ts index 6d5794fc639..ae51ffe3427 100644 --- a/packages/fuel-gauge/src/configurable-contract.test.ts +++ b/packages/fuel-gauge/src/configurable-contract.test.ts @@ -31,10 +31,8 @@ const defaultValues = { describe('Configurable Contract', () => { let wallet: WalletUnlocked; let factory: ContractFactory; - let gasPrice: BN; beforeAll(async () => { const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); const quantities: CoinQuantityLike[] = [ { amount: 1_000_000, @@ -52,7 +50,7 @@ describe('Configurable Contract', () => { }); it('should assert default values', async () => { - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); const { value } = await contract.functions.echo_configurables().simulate(); @@ -76,7 +74,7 @@ describe('Configurable Contract', () => { expect(defaultValues.U8).not.toBe(configurableConstants.U8); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_u8().simulate(); @@ -90,7 +88,7 @@ describe('Configurable Contract', () => { expect(defaultValues.U16).not.toBe(configurableConstants.U16); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_u16().simulate(); @@ -104,7 +102,7 @@ describe('Configurable Contract', () => { expect(defaultValues.U32).not.toBe(configurableConstants.U32); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_u32().simulate(); @@ -118,7 +116,7 @@ describe('Configurable Contract', () => { expect(defaultValues.U64).not.toBe(configurableConstants.U64); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_u64().simulate(); @@ -132,7 +130,7 @@ describe('Configurable Contract', () => { expect(defaultValues.BOOL).not.toBe(configurableConstants.BOOL); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_bool().simulate(); @@ -146,7 +144,7 @@ describe('Configurable Contract', () => { expect(defaultValues.B256).not.toBe(configurableConstants.B256); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_b256().simulate(); @@ -160,7 +158,7 @@ describe('Configurable Contract', () => { expect(defaultValues.ENUM).not.toBe(configurableConstants.ENUM); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_enum().simulate(); @@ -177,7 +175,7 @@ describe('Configurable Contract', () => { expect(defaultValues.ARRAY).not.toStrictEqual(configurableConstants.ARRAY); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_array().simulate(); @@ -191,7 +189,7 @@ describe('Configurable Contract', () => { expect(defaultValues.STR_4).not.toBe(configurableConstants.STR_4); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_str4().simulate(); @@ -205,7 +203,7 @@ describe('Configurable Contract', () => { expect(defaultValues.TUPLE).not.toStrictEqual(configurableConstants.TUPLE); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); const { value } = await contract.functions.echo_tuple().simulate(); @@ -223,7 +221,7 @@ describe('Configurable Contract', () => { expect(defaultValues.STRUCT_1).not.toStrictEqual(configurableConstants.STRUCT_1); - const contract = await factory.deployContract({ configurableConstants, gasPrice }); + const contract = await factory.deployContract({ configurableConstants }); 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 b2fb496a824..12e2ff4ad1f 100644 --- a/packages/fuel-gauge/src/contract-factory.test.ts +++ b/packages/fuel-gauge/src/contract-factory.test.ts @@ -18,8 +18,6 @@ import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures * @group node */ describe('Contract Factory', () => { - let gasPrice: BN; - const { binHexlified: byteCode, abiContents: abi, @@ -29,7 +27,6 @@ describe('Contract Factory', () => { const createContractFactory = async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const wallet = await generateTestWallet(provider, [[5_000_000, BaseAssetId]]); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); // send byteCode and ABI to ContractFactory to load const factory = new ContractFactory(byteCode, abi, wallet); @@ -39,7 +36,7 @@ describe('Contract Factory', () => { it('Creates a factory from inputs that can return call results', async () => { const factory = await createContractFactory(); - const contact = await factory.deployContract({ gasPrice }); + const contact = await factory.deployContract(); expect(contact.interface).toBeInstanceOf(Interface); @@ -56,7 +53,7 @@ describe('Contract Factory', () => { it('Creates a factory from inputs that can return transaction results', async () => { const factory = await createContractFactory(); - const contact = await factory.deployContract({ gasPrice }); + const contact = await factory.deployContract(); expect(contact.interface).toBeInstanceOf(Interface); @@ -99,7 +96,7 @@ describe('Contract Factory', () => { it('Creates a factory from inputs that can prepare call data', async () => { const factory = await createContractFactory(); - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); const prepared = contract.functions.increment_counter(1).getCallConfig(); expect(prepared).toEqual({ @@ -117,7 +114,6 @@ describe('Contract Factory', () => { const factory = await createContractFactory(); const contract = await factory.deployContract({ storageSlots, - gasPrice, }); const { value: var1 } = await contract.functions.return_var1().call(); @@ -146,7 +142,6 @@ describe('Contract Factory', () => { const b256 = '0x626f0c36909faecc316056fca8be684ab0cd06afc63247dc008bdf9e433f927a'; const contact = await factory.deployContract({ - gasPrice, storageSlots: [ { key: '0x0000000000000000000000000000000000000000000000000000000000000001', value: b256 }, ], @@ -161,7 +156,6 @@ describe('Contract Factory', () => { const b256 = '0x626f0c36909faecc316056fca8be684ab0cd06afc63247dc008bdf9e433f927a'; const contract = await factory.deployContract({ - gasPrice, storageSlots: [ ...storageSlots, // initializing from storage_slots.json { key: '0000000000000000000000000000000000000000000000000000000000000001', value: b256 }, // Initializing manual value diff --git a/packages/fuel-gauge/src/contract.test.ts b/packages/fuel-gauge/src/contract.test.ts index 738a20f6d1e..3d3e1a40358 100644 --- a/packages/fuel-gauge/src/contract.test.ts +++ b/packages/fuel-gauge/src/contract.test.ts @@ -225,7 +225,6 @@ describe('Contract', () => { await contract.functions .foo(1336) .txParams({ - gasPrice, gasLimit: 1, }) .call(); @@ -342,7 +341,6 @@ describe('Contract', () => { .multiCall([contract.functions.foo(1336), contract.functions.foo(1336)]) .txParams({ gasLimit: 1, - gasPrice, }) .call(); } catch (e) { @@ -413,7 +411,6 @@ describe('Contract', () => { gasLimit: 1000000, }) .txParams({ - gasPrice: 1, gasLimit: 3000000, }) .call(); @@ -436,7 +433,6 @@ describe('Contract', () => { }), ]) .txParams({ - gasPrice: 1, gasLimit: 5000000, }) .call<[BN, BN, BN]>(); @@ -459,7 +455,6 @@ describe('Contract', () => { }), ]) .txParams({ - gasPrice: 1, gasLimit: 100, }) .call<[BN, BN, BN]>() @@ -483,8 +478,8 @@ describe('Contract', () => { }), ]) .txParams({ - gasPrice: 1, gasLimit: 4_000_000, + optimizeGas: false, }) .call<[BN, BN]>(); @@ -516,8 +511,8 @@ describe('Contract', () => { const { value } = await invocationScope .txParams({ - gasPrice: transactionCost.gasPrice, gasLimit: transactionCost.gasUsed, + optimizeGas: false, }) .call<[string, string]>(); @@ -527,18 +522,15 @@ describe('Contract', () => { it('Get transaction cost with minGasPrice ', async () => { const contract = await setupContract(); const { minGasPrice } = contract.provider.getGasConfig(); - const invocationScope = contract - .multiCall([ - contract.functions.return_context_amount().callParams({ - forward: [100, BaseAssetId], - }), - contract.functions.return_context_amount().callParams({ - forward: [200, AltToken], - }), - ]) - .txParams({ - gasPrice: minGasPrice, - }); + const invocationScope = contract.multiCall([ + contract.functions.return_context_amount().callParams({ + forward: [100, BaseAssetId], + }), + contract.functions.return_context_amount().callParams({ + forward: [200, AltToken], + }), + ]); + // Get transaction cost using gasPrice from // invocation scope const transactionCost = await invocationScope.getTransactionCost(); @@ -551,7 +543,6 @@ describe('Contract', () => { // and can be used as gasLimit const { value } = await invocationScope .txParams({ - gasPrice: transactionCost.gasPrice, gasLimit: transactionCost.gasUsed, }) .call<[string, string]>(); @@ -571,7 +562,6 @@ describe('Contract', () => { await expect( invocationScope .txParams({ - gasPrice, gasLimit, }) .call() @@ -689,7 +679,6 @@ describe('Contract', () => { const struct = { a: true, b: 1337 }; const invocationScopes = [contract.functions.foo(num), contract.functions.boo(struct)]; const multiCallScope = contract.multiCall(invocationScopes).txParams({ - gasPrice, gasLimit: 20_000, }); await multiCallScope.fundWithRequiredCoins(); @@ -724,18 +713,22 @@ describe('Contract', () => { }, ]); const contract = new ContractFactory(contractBytecode, abi, wallet); - const { transactionRequest } = contract.createTransactionRequest({ gasPrice }); + const { transactionRequest } = contract.createTransactionRequest(); const txRequest = JSON.stringify(transactionRequest); const txRequestParsed = JSON.parse(txRequest); - const transactionRequestParsed = transactionRequestify(txRequestParsed); + const transactionRequestParsed = transactionRequestify( + txRequestParsed + ) as ScriptTransactionRequest; - const { requiredQuantities, maxFee } = - await provider.getTransactionCost(transactionRequestParsed); + const txCost = await provider.getTransactionCost(transactionRequestParsed); + + transactionRequestParsed.gasLimit = txCost.gasUsed; + transactionRequestParsed.maxFee = txCost.maxFee; // Fund tx - await wallet.fund(transactionRequestParsed, requiredQuantities, maxFee); + await wallet.fund(transactionRequestParsed, txCost); // Send tx const response = await wallet.sendTransaction(transactionRequestParsed); @@ -785,9 +778,7 @@ describe('Contract', () => { const num = 1337; const struct = { a: true, b: 1337 }; const invocationScopes = [contract.functions.foo(num), contract.functions.boo(struct)]; - const multiCallScope = contract - .multiCall(invocationScopes) - .txParams({ gasPrice, gasLimit: 20_000 }); + const multiCallScope = contract.multiCall(invocationScopes).txParams({ gasLimit: 20_000 }); const transactionRequest = await multiCallScope.getTransactionRequest(); @@ -798,12 +789,12 @@ describe('Contract', () => { txRequestParsed ) as ScriptTransactionRequest; - const { gasUsed, minFee, requiredQuantities } = - await contract.provider.getTransactionCost(transactionRequestParsed); + const txCost = await contract.provider.getTransactionCost(transactionRequestParsed); - transactionRequestParsed.gasLimit = gasUsed; + transactionRequestParsed.gasLimit = txCost.gasUsed; + transactionRequestParsed.maxFee = txCost.maxFee; - await contract.account.fund(transactionRequestParsed, requiredQuantities, minFee); + await contract.account.fund(transactionRequestParsed, txCost); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const response = await contract.account!.sendTransaction(transactionRequestParsed); @@ -837,7 +828,7 @@ describe('Contract', () => { ]); const factory = new ContractFactory(contractBytecode, abi, wallet); - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); const vector = [5, 4, 3, 2, 1]; @@ -868,7 +859,7 @@ describe('Contract', () => { ]); const factory = new ContractFactory(contractBytecode, abi, wallet); - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); const calls = [ contract.functions.return_bytes(), // returns heap type Bytes @@ -907,7 +898,6 @@ describe('Contract', () => { const amountToContract = u64Amount; const tx = await wallet.transferToContract(contract.id, amountToContract, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); @@ -936,18 +926,6 @@ describe('Contract', () => { ); await result.wait(); }).rejects.toThrowError(/Gas limit '1' is lower than the required: ./); - - await expect(async () => { - const result = await wallet.transferToContract( - contract.id.toB256(), - amountToContract, - BaseAssetId, - { - gasPrice: 0, - } - ); - await result.wait(); - }).rejects.toThrowError(/Gas price '0' is lower than the required: ./); }); it('should tranfer asset to a deployed contract just fine (NOT NATIVE ASSET)', async () => { @@ -965,7 +943,6 @@ describe('Contract', () => { const amountToContract = 100; const tx = await wallet.transferToContract(contract.id.toB256(), amountToContract, asset, { - gasPrice, gasLimit: 10_000, }); @@ -992,14 +969,12 @@ describe('Contract', () => { }); const tx1 = await wallet.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await tx1.waitForResult(); const tx2 = await predicate.transferToContract(contract.id, amountToContract, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); diff --git a/packages/fuel-gauge/src/coverage-contract.test.ts b/packages/fuel-gauge/src/coverage-contract.test.ts index 82e701ff7ab..75baba660f7 100644 --- a/packages/fuel-gauge/src/coverage-contract.test.ts +++ b/packages/fuel-gauge/src/coverage-contract.test.ts @@ -7,8 +7,6 @@ import { Wallet, ScriptTransactionRequest, BaseAssetId, - isMessage, - isCoin, randomBytes, hexlify, FUEL_NETWORK_URL, @@ -27,10 +25,8 @@ const B512 = const setupContract = getSetupContract('coverage-contract'); let contractInstance: Contract; -let gasPrice: BN; beforeAll(async () => { contractInstance = await setupContract(); - ({ minGasPrice: gasPrice } = contractInstance.provider.getGasConfig()); }); enum SmallEnum { @@ -484,7 +480,7 @@ describe('Coverage Contract', () => { it('should test spending input messages', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); - const request = new ScriptTransactionRequest({ gasLimit: 1000000, gasPrice }); + const request = new ScriptTransactionRequest({ gasLimit: 1000000 }); const recipient = Wallet.generate({ provider, @@ -494,14 +490,14 @@ describe('Coverage Contract', () => { provider ); - const coins = await sender.getResourcesToSpend([[bn(100), BaseAssetId]]); + request.addCoinOutput(recipient.address, 10, BaseAssetId); - expect(coins.length).toEqual(1); - expect(isMessage(coins[0])).toBeTruthy(); - expect(isCoin(coins[0])).toBeFalsy(); + const txCost = await sender.provider.getTransactionCost(request); - request.addResources(coins); - request.addCoinOutput(recipient.address, 10, BaseAssetId); + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await sender.fund(request, txCost); const response = await sender.sendTransaction(request); const result = await response.waitForResult(); diff --git a/packages/fuel-gauge/src/doc-examples.test.ts b/packages/fuel-gauge/src/doc-examples.test.ts index a79b0977275..f1032013db5 100644 --- a/packages/fuel-gauge/src/doc-examples.test.ts +++ b/packages/fuel-gauge/src/doc-examples.test.ts @@ -1,6 +1,5 @@ import { generateTestWallet, seedTestWallet } from '@fuel-ts/account/test-utils'; import type { - BN, Bech32Address, BigNumberish, Bytes, @@ -60,12 +59,6 @@ const ADDRESS_BYTES = new Uint8Array([ * @group node */ describe('Doc Examples', () => { - let gasPrice: BN; - - beforeAll(async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); - }); test('it has an Address class using bech32Address', () => { const address = new Address(ADDRESS_BECH32); @@ -265,7 +258,8 @@ describe('Doc Examples', () => { // #endregion wallet-setup }); - it('can connect to testnet', async () => { + // TODO: remove skip from testnet test + it.skip('can connect to testnet', async () => { const provider = await Provider.create(FUEL_BETA_5_NETWORK_URL); const PRIVATE_KEY = 'a1447cd75accc6b71a976fd3401a1f6ce318d27ba660b0315ee6ac347bf39568'; const wallet = Wallet.fromPrivateKey(PRIVATE_KEY, provider); @@ -434,7 +428,6 @@ describe('Doc Examples', () => { const initialPredicateBalance = await predicate.getBalance(); const response = await wallet1.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await response.waitForResult(); @@ -444,7 +437,6 @@ describe('Doc Examples', () => { expect(bn(predicateBalance)).toEqual(initialPredicateBalance.add(amountToPredicate)); const depositOnPredicate = await wallet1.transfer(predicate.address, 1000, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); // Wait for Transaction to succeed @@ -457,7 +449,6 @@ describe('Doc Examples', () => { ); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await tx.waitForResult(); diff --git a/packages/fuel-gauge/src/dry-run-multiple-txs.test.ts b/packages/fuel-gauge/src/dry-run-multiple-txs.test.ts new file mode 100644 index 00000000000..56303661f5f --- /dev/null +++ b/packages/fuel-gauge/src/dry-run-multiple-txs.test.ts @@ -0,0 +1,272 @@ +import { generateTestWallet } from '@fuel-ts/account/test-utils'; +import type { + CallResult, + EstimateTxDependenciesReturns, + TransactionResultReceipt, + WalletUnlocked, +} from 'fuels'; +import { BaseAssetId, ContractFactory, FUEL_NETWORK_URL, Provider, Wallet } from 'fuels'; + +import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; + +/** + * @group node + */ +describe('dry-run-multiple-txs', () => { + const { abiContents, binHexlified } = getFuelGaugeForcProject( + FuelGaugeProjectsEnum.TOKEN_CONTRACT + ); + const { abiContents: abiRevert, binHexlified: binRevert } = getFuelGaugeForcProject( + FuelGaugeProjectsEnum.REVERT_ERROR + ); + const { abiContents: abiMultiToken, binHexlified: binMultiToken } = getFuelGaugeForcProject( + FuelGaugeProjectsEnum.MULTI_TOKEN_CONTRACT + ); + const { abiContents: abiLog, binHexlified: binLog } = getFuelGaugeForcProject( + FuelGaugeProjectsEnum.ADVANCED_LOGGING + ); + const { abiContents: abiLogOther, binHexlified: binLogOther } = getFuelGaugeForcProject( + FuelGaugeProjectsEnum.ADVANCED_LOGGING_OTHER_CONTRACT + ); + + let provider: Provider; + let wallet: WalletUnlocked; + + beforeAll(async () => { + provider = await Provider.create(FUEL_NETWORK_URL); + wallet = await generateTestWallet(provider, [[1_000_000]]); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + const deployContracts = async () => { + const revertFactory = new ContractFactory(binRevert, abiRevert, wallet); + + const revertContract = await revertFactory.deployContract({ + maxFee: 500, + }); + + const multiTokenFactory = new ContractFactory(binMultiToken, abiMultiToken, wallet); + + const multiTokenContract = await multiTokenFactory.deployContract({ + maxFee: 500, + }); + + const logFactory = new ContractFactory(binLog, abiLog, wallet); + + const logContract = await logFactory.deployContract({ + maxFee: 500, + }); + const logOtherFactory = new ContractFactory(binLogOther, abiLogOther, wallet); + + const logOtherContract = await logOtherFactory.deployContract({ + maxFee: 500, + }); + + return { revertContract, multiTokenContract, logContract, logOtherContract }; + }; + + it('should properly dry-run multiple TXs requests', async () => { + const revertFactory = new ContractFactory(binRevert, abiRevert, wallet); + + const revertContract = await revertFactory.deployContract({ + maxFee: 500, + }); + + const resources = await wallet.getResourcesToSpend([[500_000, BaseAssetId]]); + + const request1 = await revertContract.functions + .validate_inputs(10, 0) + .txParams({ + gasLimit: 2000, + maxFee: 500, + }) + .getTransactionRequest(); + + const request2 = await revertContract.functions + .validate_inputs(0, 1) + .txParams({ + gasLimit: 2000, + maxFee: 500, + }) + .getTransactionRequest(); + + const request3 = await revertContract.functions + .validate_inputs(0, 100) + .txParams({ + gasLimit: 2000, + maxFee: 500, + }) + .getTransactionRequest(); + + request1.addResources(resources); + request2.addResources(resources); + request3.addResources(resources); + + const dryRunSpy = vi.spyOn(provider.operations, 'dryRun'); + + const estimatedRequests = await provider.dryRunMultipleTransactions( + [request1, request2, request3], + { estimateTxDependencies: false } + ); + + expect(dryRunSpy).toHaveBeenCalledTimes(1); + + expect(estimatedRequests[0]).toStrictEqual({ + receipts: expect.any(Array), + dryrunStatus: { + reason: expect.any(String), + programState: { + data: expect.any(String), + returnType: 'REVERT', + }, + }, + }); + + expect(estimatedRequests[1]).toStrictEqual({ + receipts: expect.any(Array), + dryrunStatus: { + reason: expect.any(String), + programState: { + data: expect.any(String), + returnType: 'REVERT', + }, + }, + }); + + expect(estimatedRequests[2]).toStrictEqual({ + receipts: expect.any(Array), + dryrunStatus: { + reason: expect.any(String), + programState: { + data: expect.any(String), + returnType: 'REVERT', + }, + }, + }); + }); + + it('should properly estimate multiple TXs requests', async () => { + // preparing test data + const { revertContract, multiTokenContract, logContract, logOtherContract } = + await deployContracts(); + + // subId defined on multi-token contract + const subId = '0x4a778acfad1abc155a009dc976d2cf0db6197d3d360194d74b1fb92b96986b00'; + const resources = await wallet.getResourcesToSpend([[500_000, BaseAssetId]]); + + // creating receives to be used by the request 2 and 3 + const addresses = [ + { value: Wallet.generate({ provider }).address.toB256() }, + { value: Wallet.generate({ provider }).address.toB256() }, + { value: Wallet.generate({ provider }).address.toB256() }, + ]; + + // request 1 + const factory = new ContractFactory(binHexlified, abiContents, wallet); + const { transactionRequest: request1 } = factory.createTransactionRequest({ + maxFee: 500, + }); + + // request 2 + const request2 = await multiTokenContract.functions + .mint_to_addresses(addresses, subId, 1000) + .txParams({ + gasLimit: 2000, + maxFee: 500, + variableOutputs: 0, + }) + .getTransactionRequest(); + + // request 3 + const request3 = await multiTokenContract.functions + .mint_to_addresses(addresses, subId, 2000) + .txParams({ + gasLimit: 2000, + maxFee: 500, + variableOutputs: 1, + }) + .getTransactionRequest(); + + // request 4 + const request4 = await revertContract.functions + .failed_transfer_revert() + .txParams({ + gasLimit: 2000, + maxFee: 500, + variableOutputs: 1, + }) + .getTransactionRequest(); + + // request 5 + const request5 = await logContract.functions + .test_log_from_other_contract(10, logOtherContract.id.toB256()) + .txParams({ + gasLimit: 2000, + maxFee: 500, + }) + .getTransactionRequest(); + + /** + * Adding same resources to all request (it only works because we estimate + * requests using the dry run flag utxo_validation: false) + */ + request1.addResources(resources); + request2.addResources(resources); + request3.addResources(resources); + request4.addResources(resources); + request5.addResources(resources); + + const dryRunSpy = vi.spyOn(provider.operations, 'dryRun'); + + const estimatedRequests = await provider.dryRunMultipleTransactions( + [request1, request2, request3, request4, request5], + { estimateTxDependencies: true } + ); + + expect(dryRunSpy).toHaveBeenCalledTimes(4); + expect(estimatedRequests.length).toBe(5); + + // request 1 for create transaction request, we do not dry run + expect(estimatedRequests[0]).toStrictEqual({ + receipts: [], + missingContractIds: [], + outputVariables: 0, + dryrunStatus: undefined, + }); + + // request 2 we dry run it 4 times to add the 3 output variables + expect(estimatedRequests[1]).toStrictEqual({ + receipts: expect.any(Array), + missingContractIds: [], + outputVariables: 3, + dryrunStatus: { programState: expect.any(Object) }, + }); + + // request 3 we dry run it 3 times to add the 2 output variables (1 was already present) + expect(estimatedRequests[2]).toStrictEqual({ + receipts: expect.any(Array), + missingContractIds: [], + outputVariables: 2, + dryrunStatus: { programState: expect.any(Object) }, + }); + + // request 4 we dry run it 1 time because it has reveted + expect(estimatedRequests[3]).toStrictEqual({ + receipts: expect.any(Array), + missingContractIds: [], + outputVariables: 0, + dryrunStatus: { reason: 'TransferZeroCoins', programState: expect.any(Object) }, + }); + + // request 5 we dry run it 2 times because to add the missing output contract + expect(estimatedRequests[4]).toStrictEqual({ + receipts: expect.any(Array), + missingContractIds: [logOtherContract.id.toB256()], + outputVariables: 0, + dryrunStatus: { programState: expect.any(Object) }, + }); + }); +}); diff --git a/packages/fuel-gauge/src/edge-cases.test.ts b/packages/fuel-gauge/src/edge-cases.test.ts index af32cbcb027..1307c02699c 100644 --- a/packages/fuel-gauge/src/edge-cases.test.ts +++ b/packages/fuel-gauge/src/edge-cases.test.ts @@ -25,7 +25,7 @@ describe('Edge Cases', () => { destination.address, 100, BaseAssetId, - { gasPrice: provider.getGasConfig().minGasPrice, gasLimit: 10_000 } + { gasLimit: 10_000 } ); const response = new TransactionResponse(transactionId, provider); diff --git a/packages/fuel-gauge/src/experimental-logging.test.ts b/packages/fuel-gauge/src/experimental-logging.test.ts index a54a67609c2..3a2bfec4848 100644 --- a/packages/fuel-gauge/src/experimental-logging.test.ts +++ b/packages/fuel-gauge/src/experimental-logging.test.ts @@ -1,13 +1,12 @@ import { randomBytes } from 'crypto'; import { readFileSync } from 'fs'; -import type { BN, Contract } from 'fuels'; +import type { Contract } from 'fuels'; import { bn, hexlify } from 'fuels'; import { join } from 'path'; import { setup } from './utils'; let contractInstance: Contract; -let gasPrice: BN; const U8_MAX = 2 ** 8 - 1; const U16_MAX = 2 ** 16 - 1; @@ -26,8 +25,6 @@ beforeAll(async () => { const abi = JSON.parse(readFileSync(`${path}-abi.json`, 'utf8')); contractInstance = await setup({ contractBytecode, abi }); - - ({ minGasPrice: gasPrice } = contractInstance.provider.getGasConfig()); }); /** @@ -39,7 +36,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u8(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toStrictEqual([expected]); @@ -50,7 +47,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u16(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toStrictEqual([expected]); @@ -61,7 +58,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u32(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toStrictEqual([expected]); @@ -72,7 +69,7 @@ describe('Experimental Logging', () => { const { value, logs } = await contractInstance.functions .log_u8_u16_u32(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(value).toEqual(expected); @@ -84,7 +81,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u64(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(bn(logs[0]).toNumber()).toStrictEqual(expected); @@ -103,7 +100,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u64_u8(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(bn(logs[0]).toNumber()).toStrictEqual(expected[0]); @@ -115,7 +112,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_boolean(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toStrictEqual([expected]); @@ -126,7 +123,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_boolean_boolean(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual(expected); @@ -137,7 +134,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_number_boolean(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual(expected); @@ -148,7 +145,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_b256(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toStrictEqual([expected]); @@ -159,7 +156,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_b512(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toStrictEqual([expected]); @@ -170,7 +167,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_b256_b512(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual(expected); @@ -181,7 +178,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_vec_u8(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -192,7 +189,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_vec_b256(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -203,7 +200,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_bytes(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([Uint8Array.from(expected)]); @@ -214,7 +211,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_std_string(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -225,7 +222,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u16_bytes(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([U16_MAX, Uint8Array.from([40, 41, 42])]); @@ -236,7 +233,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u8_array(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -247,7 +244,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u16_array(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -258,7 +255,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u16_u8_array(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual(expected); @@ -269,7 +266,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_str_4(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -280,7 +277,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u8_str_2(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual(expected); @@ -291,7 +288,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_u8_u16_tuple(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -303,12 +300,12 @@ describe('Experimental Logging', () => { const { logs: logsFoo } = await contractInstance.functions .log_enum(expectedFoo) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); const { logs: logsBar } = await contractInstance.functions .log_enum(expectedBar) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logsFoo).toEqual([expectedFoo]); @@ -321,12 +318,12 @@ describe('Experimental Logging', () => { const { logs: logsFoo } = await contractInstance.functions .log_native_enum(expectedFoo) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); const { logs: logsBar } = await contractInstance.functions .log_native_enum(expectedBar) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logsFoo).toEqual([expectedFoo]); @@ -338,7 +335,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_boolean_enum(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual(expected); @@ -352,7 +349,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_struct(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -372,7 +369,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_struct_vec(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -389,7 +386,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_struct_boolean(...expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual(expected); @@ -401,12 +398,12 @@ describe('Experimental Logging', () => { const { logs: logsSome } = await contractInstance.functions .log_option_u8(expectedSome) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); const { logs: logsNone } = await contractInstance.functions .log_option_u8(expectedNone) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logsSome).toEqual([expectedSome]); @@ -418,7 +415,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_raw_slice(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); @@ -430,7 +427,7 @@ describe('Experimental Logging', () => { const { logs } = await contractInstance.functions .log_str_slice(expected) - .txParams({ gasPrice, gasLimit: 10_000 }) + .txParams({ gasLimit: 10_000 }) .call(); expect(logs).toEqual([expected]); diff --git a/packages/fuel-gauge/src/fee.test.ts b/packages/fuel-gauge/src/fee.test.ts index 8e1435afe8d..48fa1f2d0e0 100644 --- a/packages/fuel-gauge/src/fee.test.ts +++ b/packages/fuel-gauge/src/fee.test.ts @@ -1,6 +1,6 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; import { ASSET_A, ASSET_B, expectToBeInRange } from '@fuel-ts/utils/test-utils'; -import type { BN, BaseWalletUnlocked, CoinQuantityLike } from 'fuels'; +import type { BN, BaseWalletUnlocked } from 'fuels'; import { BaseAssetId, ContractFactory, @@ -9,7 +9,6 @@ import { Provider, ScriptTransactionRequest, Wallet, - bn, } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; @@ -20,11 +19,9 @@ import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures describe('Fee', () => { let wallet: BaseWalletUnlocked; let provider: Provider; - let minGasPrice: number; beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); - minGasPrice = provider.getGasConfig().minGasPrice.toNumber(); wallet = await generateTestWallet(provider, [ [1_000_000_000], [1_000_000_000, ASSET_A], @@ -49,29 +46,22 @@ describe('Fee', () => { } }; - const randomGasPrice = (minValue: number, maxValue: number) => { - const randomValue = Math.floor(Math.random() * (maxValue - minValue + 1) + minValue); - return bn(randomValue); - }; - it('should ensure fee is properly calculated when minting and burning coins', async () => { const { binHexlified, abiContents } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.MULTI_TOKEN_CONTRACT ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract({ gasPrice: minGasPrice }); + const contract = await factory.deployContract(); // minting coins let balanceBefore = await wallet.getBalance(); - let gasPrice = randomGasPrice(minGasPrice, 7); - const subId = '0x4a778acfad1abc155a009dc976d2cf0db6197d3d360194d74b1fb92b96986b00'; const { transactionResult: { fee: fee1 }, - } = await contract.functions.mint_coins(subId, 1_000).txParams({ gasPrice }).call(); + } = await contract.functions.mint_coins(subId, 1_000).call(); let balanceAfter = await wallet.getBalance(); @@ -82,11 +72,9 @@ describe('Fee', () => { // burning coins balanceBefore = await wallet.getBalance(); - gasPrice = randomGasPrice(minGasPrice, 7); - const { transactionResult: { fee: fee2 }, - } = await contract.functions.mint_coins(subId, 1_000).txParams({ gasPrice }).call(); + } = await contract.functions.mint_coins(subId, 1_000).call(); balanceAfter = await wallet.getBalance(); @@ -101,10 +89,7 @@ describe('Fee', () => { const amountToTransfer = 120; const balanceBefore = await wallet.getBalance(); - const gasPrice = randomGasPrice(minGasPrice, 7); - const tx = await wallet.transfer(destination.address, amountToTransfer, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); const { fee } = await tx.wait(); @@ -125,11 +110,9 @@ describe('Fee', () => { const destination3 = Wallet.generate({ provider }); const amountToTransfer = 120; - const gasPrice = randomGasPrice(minGasPrice, 7); const balanceBefore = await wallet.getBalance(); const request = new ScriptTransactionRequest({ - gasPrice, gasLimit: 10000, }); @@ -137,15 +120,14 @@ describe('Fee', () => { request.addCoinOutput(destination2.address, amountToTransfer, ASSET_A); request.addCoinOutput(destination3.address, amountToTransfer, ASSET_B); - const quantities: CoinQuantityLike[] = [ - [20_000 + amountToTransfer, BaseAssetId], - [amountToTransfer, ASSET_A], - [amountToTransfer, ASSET_B], - ]; + const txCost = await provider.getTransactionCost(request, { + resourcesOwner: wallet, + }); - const resources = await wallet.getResourcesToSpend(quantities); + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - request.addResources(resources); + await wallet.fund(request, txCost); const tx = await wallet.sendTransaction(request); const { fee } = await tx.wait(); @@ -167,12 +149,13 @@ describe('Fee', () => { const balanceBefore = await wallet.getBalance(); - const gasPrice = randomGasPrice(minGasPrice, 7); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const { transactionRequest } = factory.createTransactionRequest({ gasPrice }); - const { maxFee, requiredQuantities } = await provider.getTransactionCost(transactionRequest); + const { transactionRequest } = factory.createTransactionRequest(); + const txCost = await provider.getTransactionCost(transactionRequest); + + transactionRequest.maxFee = txCost.maxFee; - await wallet.fund(transactionRequest, requiredQuantities, maxFee); + await wallet.fund(transactionRequest, txCost); const tx = await wallet.sendTransaction(transactionRequest); const { fee } = await tx.wait(); @@ -193,18 +176,15 @@ describe('Fee', () => { ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract({ gasPrice: minGasPrice }); + const contract = await factory.deployContract(); - const gasPrice = randomGasPrice(minGasPrice, 7); const balanceBefore = await wallet.getBalance(); const { transactionResult: { fee }, } = await contract.functions .sum_multparams(1, 2, 3, 4, 5) - .txParams({ - gasPrice, - }) + .call(); const balanceAfter = await wallet.getBalance(); @@ -223,9 +203,8 @@ describe('Fee', () => { ); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const contract = await factory.deployContract({ gasPrice: minGasPrice }); + const contract = await factory.deployContract(); - const gasPrice = randomGasPrice(minGasPrice, 7); const balanceBefore = await wallet.getBalance(); const scope = contract @@ -236,7 +215,6 @@ describe('Fee', () => { contract.functions.return_bytes(), ]) .txParams({ - gasPrice, gasLimit: 10000, }); @@ -256,28 +234,22 @@ describe('Fee', () => { it('should ensure fee is properly calculated on transactions with predicate', async () => { const { binHexlified, abiContents } = getFuelGaugeForcProject( - FuelGaugeProjectsEnum.PREDICATE_TRUE + FuelGaugeProjectsEnum.PREDICATE_U32 ); const predicate = new Predicate({ bytecode: binHexlified, abi: abiContents, provider, + inputData: [1078], }); - const tx1 = await wallet.transfer(predicate.address, 1_500_000, BaseAssetId, { - gasPrice: minGasPrice, - gasLimit: 10_000, - }); + const tx1 = await wallet.transfer(predicate.address, 2000, BaseAssetId); await tx1.wait(); const transferAmount = 100; const balanceBefore = await predicate.getBalance(); - const gasPrice = randomGasPrice(minGasPrice, 9); - const tx2 = await predicate.transfer(wallet.address, transferAmount, BaseAssetId, { - gasPrice, - gasLimit: 10_000, - }); + const tx2 = await predicate.transfer(wallet.address, transferAmount, BaseAssetId); const { fee } = await tx2.wait(); diff --git a/packages/fuel-gauge/src/funding-transaction.test.ts b/packages/fuel-gauge/src/funding-transaction.test.ts index de668652509..f7ef88a6668 100644 --- a/packages/fuel-gauge/src/funding-transaction.test.ts +++ b/packages/fuel-gauge/src/funding-transaction.test.ts @@ -30,10 +30,7 @@ describe(__filename, () => { totalAmount: number; splitIn: number; }) => { - const request = new ScriptTransactionRequest({ - gasLimit: 1_000, - gasPrice: bn(10), - }); + const request = new ScriptTransactionRequest(); for (let i = 0; i < splitIn; i++) { request.addCoinOutput(account.address, totalAmount / splitIn, BaseAssetId); @@ -42,6 +39,13 @@ describe(__filename, () => { const resources = await mainWallet.getResourcesToSpend([[totalAmount + 2_000, BaseAssetId]]); request.addResources(resources); + const txCost = await mainWallet.provider.getTransactionCost(request); + + request.maxFee = txCost.maxFee; + request.gasLimit = txCost.gasUsed; + + await mainWallet.fund(request, txCost); + const tx = await mainWallet.sendTransaction(request); await tx.waitForResult(); }; @@ -57,33 +61,22 @@ describe(__filename, () => { splitIn: 5, }); - // this will return one UTXO of 300, not enought to pay for the TX fees - const lowResources = await sender.getResourcesToSpend([[100, BaseAssetId]]); - - // confirm we only fetched 1 UTXO from the expected amount - expect(lowResources.length).toBe(1); - expect(lowResources[0].amount.toNumber()).toBe(300); - const request = new ScriptTransactionRequest({ gasLimit: 1_000, - gasPrice: bn(10), }); const amountToTransfer = 300; - request.addCoinOutput(receiver.address, amountToTransfer, BaseAssetId); - request.addResources(lowResources); + request.addCoinOutput(receiver.address, amountToTransfer, BaseAssetId); - const { maxFee, requiredQuantities } = await provider.getTransactionCost(request); - - // TX request already does NOT carries enough resources, it needs to be funded - expect(request.inputs.length).toBe(1); - expect(bn((request.inputs[0]).amount).toNumber()).toBe(300); - expect(maxFee.gt(300)).toBeTruthy(); + const txCost = await provider.getTransactionCost(request); const getResourcesToSpendSpy = vi.spyOn(sender, 'getResourcesToSpend'); - await sender.fund(request, requiredQuantities, maxFee); + request.maxFee = txCost.maxFee; + request.gasLimit = txCost.gasUsed; + + await sender.fund(request, txCost); const tx = await sender.sendTransaction(request); @@ -117,7 +110,6 @@ describe(__filename, () => { const request = new ScriptTransactionRequest({ gasLimit: 1_000, - gasPrice: bn(10), }); const amountToTransfer = 100; @@ -125,16 +117,19 @@ describe(__filename, () => { request.addCoinOutput(receiver.address, amountToTransfer, BaseAssetId); request.addResources(enoughtResources); - const { maxFee, requiredQuantities } = await provider.getTransactionCost(request); + const txCost = await provider.getTransactionCost(request); // TX request already carries enough resources, it does not need to be funded expect(request.inputs.length).toBe(1); expect(bn((request.inputs[0]).amount).toNumber()).toBe(1000); - expect(maxFee.lt(1000)).toBeTruthy(); + expect(txCost.maxFee.lt(1000)).toBeTruthy(); const getResourcesToSpendSpy = vi.spyOn(sender, 'getResourcesToSpend'); - await sender.fund(request, requiredQuantities, maxFee); + request.maxFee = txCost.maxFee; + request.gasLimit = txCost.gasUsed; + + await sender.fund(request, txCost); const tx = await sender.sendTransaction(request); @@ -161,20 +156,19 @@ describe(__filename, () => { const request = new ScriptTransactionRequest({ gasLimit: 1_000, - gasPrice: bn(10), }); const amountToTransfer = 1000; request.addCoinOutput(receiver.address, amountToTransfer, BaseAssetId); - const { maxFee, requiredQuantities } = await provider.getTransactionCost(request); + const txCost = await provider.getTransactionCost(request); // TX request does NOT carry any resources, it needs to be funded expect(request.inputs.length).toBe(0); const getResourcesToSpendSpy = vi.spyOn(sender, 'getResourcesToSpend'); - await sender.fund(request, requiredQuantities, maxFee); + await sender.fund(request, txCost); const tx = await sender.sendTransaction(request); diff --git a/packages/fuel-gauge/src/min-gas.test.ts b/packages/fuel-gauge/src/min-gas.test.ts index 98d605850b5..1ba5bd604f3 100644 --- a/packages/fuel-gauge/src/min-gas.test.ts +++ b/packages/fuel-gauge/src/min-gas.test.ts @@ -52,8 +52,9 @@ describe(__filename, () => { /** * Get the transaction cost to set a strict gasLimit and min gasPrice */ - const txCost = await provider.getTransactionCost(request); - request.gasPrice = txCost.gasPrice; + const { maxFee } = await provider.getTransactionCost(request); + + request.maxFee = maxFee; /** * Send transaction @@ -86,12 +87,12 @@ describe(__filename, () => { /** * Get the transaction cost to set a strict gasLimit and min gasPrice */ - const costs = await provider.getTransactionCost(request); + const txCost = await provider.getTransactionCost(request); - await sender.fund(request, costs.requiredQuantities, costs.maxFee); + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - request.gasLimit = bn(20_000); - request.gasPrice = costs.gasPrice; + await sender.fund(request, txCost); /** * Send transaction @@ -100,7 +101,7 @@ describe(__filename, () => { const { status, gasUsed: txGasUsed } = await result.wait(); expect(status).toBe(TransactionStatus.success); - expect(costs.gasUsed.toString()).toBe(txGasUsed.toString()); + expect(txCost.gasUsed.toString()).toBe(txGasUsed.toString()); }); it('sets gas requirements (predicate)', async () => { @@ -118,6 +119,7 @@ describe(__filename, () => { provider, inputData: [bn(1000)], }); + await seedTestWallet(predicate, [[500_000, BaseAssetId]]); /** @@ -125,30 +127,26 @@ describe(__filename, () => { */ const request = new ScriptTransactionRequest(); request.addCoinOutput(Address.fromRandom(), bn(100), BaseAssetId); - const resources = await provider.getResourcesToSpend(predicate.address, [ - { - amount: bn(100_000), - assetId: BaseAssetId, - }, - ]); - request.addResources(resources); /** * Get the transaction cost to set a strict gasLimit and min gasPrice */ - const txCost = await provider.getTransactionCost(request); + const txCost = await provider.getTransactionCost(request, { resourcesOwner: predicate }); + request.gasLimit = txCost.gasUsed; - request.gasPrice = txCost.gasPrice; + request.maxFee = txCost.maxFee; + + await predicate.fund(request, txCost); /** * Send transaction predicate */ const result = await predicate.sendTransaction(request); const { status, receipts } = await result.waitForResult(); - const gasUsed = getGasUsedFromReceipts(receipts); + const gasUsedFromReceipts = getGasUsedFromReceipts(receipts); expect(status).toBe(TransactionStatus.success); - expect(gasUsed.toString()).toBe(txCost.gasUsed.toString()); + expect(txCost.gasUsed.toString()).toBe(gasUsedFromReceipts.toString()); }); it('sets gas requirements (account and predicate with script)', async () => { @@ -187,30 +185,30 @@ describe(__filename, () => { scriptData: hexlify(new BigNumberCoder('u64').encode(bn(2000))), }); // add predicate transfer - request.addCoinOutput(Address.fromRandom(), bn(100), BaseAssetId); - const resourcesPredicate = await provider.getResourcesToSpend(predicate.address, [ + const resourcesPredicate = await predicate.getResourcesToSpend([ { amount: bn(100_000), assetId: BaseAssetId, }, ]); - request.addPredicateResources(resourcesPredicate, predicate); + request.addResources(resourcesPredicate); + // add account transfer request.addCoinOutput(Address.fromRandom(), bn(100), BaseAssetId); - const resourcesWallet = await provider.getResourcesToSpend(wallet.address, [ - { - amount: bn(100_000), - assetId: BaseAssetId, - }, - ]); - request.addResources(resourcesWallet); + + const txCost = await provider.getTransactionCost(request, { + resourcesOwner: predicate, + }); + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await wallet.provider.estimatePredicates(request); + + await wallet.fund(request, txCost); /** * Get the transaction cost to set a strict gasLimit and min gasPrice */ - const txCost = await provider.getTransactionCost(request); - request.gasLimit = txCost.gasUsed; - request.gasPrice = txCost.gasPrice; /** * Send transaction predicate @@ -218,10 +216,10 @@ describe(__filename, () => { predicate.populateTransactionPredicateData(request); await wallet.populateTransactionWitnessesSignature(request); const result = await predicate.sendTransaction(request); - const { status, receipts } = await result.waitForResult(); - const gasUsed = getGasUsedFromReceipts(receipts); + const { status, receipts } = await result.wait(); + const txGasUsed = getGasUsedFromReceipts(receipts); expect(status).toBe(TransactionStatus.success); - expect(gasUsed.toString()).toBe(txCost.gasUsed.toString()); + expect(txCost.gasUsed.toString()).toBe(txGasUsed.toString()); }); }); diff --git a/packages/fuel-gauge/src/multi-token-contract.test.ts b/packages/fuel-gauge/src/multi-token-contract.test.ts index f28fabb97a4..27415360c74 100644 --- a/packages/fuel-gauge/src/multi-token-contract.test.ts +++ b/packages/fuel-gauge/src/multi-token-contract.test.ts @@ -14,8 +14,7 @@ const setup = async () => { ); const factory = new ContractFactory(bytecode, abi, wallet); - const { minGasPrice: gasPrice } = wallet.provider.getGasConfig(); - const contract = await factory.deployContract({ gasPrice }); + const contract = await factory.deployContract(); return contract; }; diff --git a/packages/fuel-gauge/src/policies.test.ts b/packages/fuel-gauge/src/policies.test.ts index 703856bb5c7..15f3cf0b873 100644 --- a/packages/fuel-gauge/src/policies.test.ts +++ b/packages/fuel-gauge/src/policies.test.ts @@ -1,5 +1,5 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; -import type { BigNumberish, Transaction } from 'fuels'; +import type { BigNumberish, Transaction, WalletUnlocked } from 'fuels'; import { BaseAssetId, ContractFactory, @@ -21,14 +21,16 @@ import { createSetupConfig } from './utils'; */ describe('Policies', () => { let provider: Provider; + let wallet: WalletUnlocked; beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); + wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); }); type CustomTxParams = { - gasPrice: BigNumberish; gasLimit?: BigNumberish; maturity?: number; + tip?: BigNumberish; maxFee?: BigNumberish; witnessLimit?: BigNumberish; }; @@ -45,35 +47,40 @@ describe('Policies', () => { transaction: Transaction; params: CustomTxParams; }) => { - expect(transaction.policies?.[0].type).toBe(PolicyType.GasPrice); - expect(bn(transaction.policies?.[0].data).eq(params.gasPrice)).toBeTruthy(); + expect(transaction.policies?.[0].type).toBe(PolicyType.Tip); + expect(bn(transaction.policies?.[0].data).eq(bn(params.tip))).toBeTruthy(); expect(transaction.policies?.[1].type).toBe(PolicyType.WitnessLimit); expect(bn(transaction.policies?.[1].data).eq(bn(params.witnessLimit))).toBeTruthy(); expect(transaction.policies?.[2].type).toBe(PolicyType.Maturity); expect(transaction.policies?.[2]?.data).toBe(params.maturity); expect(transaction.policies?.[3].type).toBe(PolicyType.MaxFee); - expect(bn(transaction.policies?.[3].data).eq(bn(params.maxFee))).toBeTruthy(); + expect(bn(transaction.policies?.[3].data)).toBeTruthy(); }; it('should ensure TX policies are properly set (ScriptTransactionRequest)', async () => { - const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); const receiver = Wallet.generate({ provider }); + const setGasLimit = 400; + const setMaxFee = 200; + const txRequest = new ScriptTransactionRequest({ - gasLimit: randomNumber(800, 1_000), + gasLimit: setGasLimit, maturity: randomNumber(1, 2), - gasPrice: randomNumber(1, 3), witnessLimit: randomNumber(800, 900), - maxFee: randomNumber(9_000, 10_000), + maxFee: setMaxFee, }); + expect(txRequest.gasLimit.toNumber()).toBe(setGasLimit); + expect(txRequest.maxFee?.toNumber()).toBe(setMaxFee); + txRequest.addCoinOutput(receiver.address, 500, BaseAssetId); - const { gasUsed, maxFee, requiredQuantities } = await provider.getTransactionCost(txRequest); + const txCost = await provider.getTransactionCost(txRequest); - txRequest.gasLimit = gasUsed; + txRequest.gasLimit = txCost.gasUsed; + txRequest.maxFee = txCost.maxFee; - await wallet.fund(txRequest, requiredQuantities, maxFee); + await wallet.fund(txRequest, txCost); const tx = await wallet.sendTransaction(txRequest); @@ -93,20 +100,18 @@ describe('Policies', () => { FuelGaugeProjectsEnum.SCRIPT_MAIN_ARGS ); - const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); - const factory = new ContractFactory(binHexlified, abiContents, wallet); const { transactionRequest: txRequest } = factory.createTransactionRequest({ maturity: randomNumber(1, 2), - gasPrice: randomNumber(1, 3), witnessLimit: randomNumber(800, 900), - maxFee: randomNumber(9_000, 10_000), }); - const { maxFee, requiredQuantities } = await provider.getTransactionCost(txRequest); + const txCost = await provider.getTransactionCost(txRequest); - await wallet.fund(txRequest, requiredQuantities, maxFee); + txRequest.maxFee = txCost.maxFee; + + await wallet.fund(txRequest, txCost); const tx = await wallet.sendTransaction(txRequest); @@ -129,16 +134,18 @@ describe('Policies', () => { cache: true, })(); + const gasLimit = randomNumber(800, 1_000); + const callScope = contract.functions.payable().txParams({ - gasLimit: randomNumber(800, 1_000), + gasLimit, maturity: randomNumber(1, 2), - gasPrice: randomNumber(1, 3), witnessLimit: randomNumber(800, 900), - maxFee: randomNumber(9_000, 10_000), }); const txRequest = await callScope.getTransactionRequest(); + expect(txRequest.gasLimit.toNumber()).toBe(gasLimit); + const { transactionResult: { transaction }, } = await callScope.call(); @@ -153,7 +160,6 @@ describe('Policies', () => { const { binHexlified, abiContents } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.SCRIPT_MAIN_ARGS ); - const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); const scriptInstance = new Script( binHexlified, @@ -161,16 +167,18 @@ describe('Policies', () => { wallet ); + const setGasLimit = randomNumber(800, 1_000); + const callScope = scriptInstance.functions.main(33).txParams({ - gasLimit: randomNumber(800, 1_000), + gasLimit: setGasLimit, maturity: randomNumber(1, 2), - gasPrice: randomNumber(1, 3), witnessLimit: randomNumber(800, 900), - maxFee: randomNumber(9_000, 10_000), }); const txRequest = await callScope.getTransactionRequest(); + expect(txRequest.gasLimit.toNumber()).toBe(setGasLimit); + const { transactionResult: { transaction }, } = await callScope.call(); @@ -182,17 +190,18 @@ describe('Policies', () => { }); it('should ensure TX policies are properly set (Account Transfer)', async () => { - const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); const receiver = Wallet.generate({ provider }); + const setGasLimit = randomNumber(800, 1_000); + const txParams: CustomTxParams = { - gasLimit: randomNumber(800, 1_000), + gasLimit: setGasLimit, maturity: randomNumber(1, 2), - gasPrice: randomNumber(1, 3), witnessLimit: randomNumber(800, 900), - maxFee: randomNumber(9_000, 10_000), }; + expect(txParams.gasLimit).toBe(setGasLimit); + const pendingTx = await wallet.transfer(receiver.address, 500, BaseAssetId, txParams); const { transaction } = await pendingTx.waitForResult(); @@ -214,14 +223,10 @@ describe('Policies', () => { cache: true, })(); - const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); - const txParams: CustomTxParams = { gasLimit: randomNumber(800, 1_000), maturity: randomNumber(1, 2), - gasPrice: randomNumber(1, 3), witnessLimit: randomNumber(800, 900), - maxFee: randomNumber(9_000, 10_000), }; const pendingTx = await wallet.transferToContract(contract.id, 500, BaseAssetId, txParams); @@ -235,15 +240,12 @@ describe('Policies', () => { }); it('should ensure TX witnessLimit rule limits tx execution as expected', async () => { - const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); const receiver = Wallet.generate({ provider }); const txParams: CustomTxParams = { gasLimit: randomNumber(800, 1_000), maturity: randomNumber(1, 2), - gasPrice: randomNumber(1, 3), witnessLimit: 5, - maxFee: randomNumber(9_000, 10_000), }; await expect(async () => { @@ -252,23 +254,4 @@ describe('Policies', () => { await pendingTx.waitForResult(); }).rejects.toThrow(/TransactionWitnessLimitExceeded/); }); - - it('should ensure TX maxFee rule limits tx execution as Expected', async () => { - const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); - const receiver = Wallet.generate({ provider }); - - const txParams: CustomTxParams = { - gasLimit: randomNumber(800, 1_000), - maturity: randomNumber(1, 2), - gasPrice: randomNumber(1, 3), - witnessLimit: randomNumber(800, 900), - maxFee: 5, - }; - - await expect(async () => { - const pendingTx = await wallet.transfer(receiver.address, 500, BaseAssetId, txParams); - - await pendingTx.waitForResult(); - }).rejects.toThrow(/TransactionMaxFeeLimitExceeded/); - }); }); diff --git a/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts b/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts index 24bebc050ff..63d2f8bb803 100644 --- a/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts +++ b/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts @@ -1,6 +1,5 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils'; -import type { BN } from 'fuels'; import { Provider, FUEL_NETWORK_URL, @@ -17,17 +16,10 @@ import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures * @group node */ describe('PredicateConditionalInputs', () => { - let gasPrice: BN; - const { binHexlified: predicateBytecode, abiContents: abiJSON } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.PREDICATE_CONDITIONAL_INPUTS ); - beforeAll(async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); - }); - it('should execute custom transaction where predicate transfers to Alice (ALICE PAYS FEES)', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); @@ -50,37 +42,33 @@ describe('PredicateConditionalInputs', () => { }); // transfer asset A to predicate so it can transfer to alice - const tx1 = await adminWallet.transfer(predicate.address, 100_000, ASSET_A, { - gasPrice, - gasLimit: 10_000, - }); + const tx1 = await adminWallet.transfer(predicate.address, 100_000, ASSET_A); await tx1.waitForResult(); // transfer base asset to Alice so she can pay the fees - const tx2 = await adminWallet.transfer(aliceWallet.address, 2_000, BaseAssetId, { - gasPrice, - gasLimit: 10_000, - }); + const tx2 = await adminWallet.transfer(aliceWallet.address, 2_000, BaseAssetId); await tx2.waitForResult(); - const request = new ScriptTransactionRequest({ - gasLimit: 1000, - gasPrice: 1, - }); + const request = new ScriptTransactionRequest(); // fetch predicate resources to spend const predicateResoruces = await predicate.getResourcesToSpend([[amountToTransfer, ASSET_A]]); - // fetch Alice resources to spend - const aliceResources = await aliceWallet.getResourcesToSpend([[request.gasLimit, BaseAssetId]]); - request - .addResources(aliceResources) - .addPredicateResources(predicateResoruces, predicate) + .addResources(predicateResoruces) .addCoinOutput(aliceWallet.address, amountToTransfer, ASSET_A); + const txCost = await aliceWallet.provider.getTransactionCost(request, { + resourcesOwner: aliceWallet, + }); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await aliceWallet.fund(request, { ...txCost, requiredQuantities: [] }); + const aliceBaseAssetBefore = await aliceWallet.getBalance(); const aliceAssetABefore = await aliceWallet.getBalance(ASSET_A); const predicateAssetABefore = await predicate.getBalance(ASSET_A); @@ -130,40 +118,25 @@ describe('PredicateConditionalInputs', () => { }); // transfer asset A to predicate so it can transfer to alice - const tx1 = await adminWallet.transfer(predicate.address, 2_000, ASSET_A, { - gasPrice, - gasLimit: 10_000, - }); + const tx1 = await adminWallet.transfer(predicate.address, 2_000, ASSET_A); await tx1.waitForResult(); // transfer base asset to predicate so it can pay the fees - const tx2 = await adminWallet.transfer(predicate.address, 2_000, BaseAssetId, { - gasPrice, - gasLimit: 10_000, - }); + const tx2 = await adminWallet.transfer(predicate.address, 2_000, BaseAssetId); await tx2.waitForResult(); // transfer asset B to Alice so it can add symbolic UTXOs to the transaction // inputs in order to the predicate validate her inputs in the transaction. - const tx3 = await adminWallet.transfer(aliceWallet.address, 2_000, ASSET_B, { - gasPrice, - gasLimit: 10_000, - }); + const tx3 = await adminWallet.transfer(aliceWallet.address, 2_000, ASSET_B); await tx3.waitForResult(); - const request = new ScriptTransactionRequest({ - gasLimit: 1000, - gasPrice: 1, - }); + const request = new ScriptTransactionRequest(); // predicate will pay the fee so it will need the base asset - const predicateResources = await predicate.getResourcesToSpend([ - [amountToTransfer, ASSET_A], - [1000, BaseAssetId], - ]); + const predicateResources = await predicate.getResourcesToSpend([[amountToTransfer, ASSET_A]]); /** * we need to add Alice resources in order to the predicate validates that she have inputs @@ -173,9 +146,21 @@ describe('PredicateConditionalInputs', () => { request .addResources(aliceResources) - .addPredicateResources(predicateResources, predicate) + .addResources(predicateResources) .addCoinOutput(aliceWallet.address, amountToTransfer, ASSET_A); + const txCost = await aliceWallet.provider.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + // predicate will pay for the transaction fee + await predicate.fund(request, txCost); + + predicate.populateTransactionPredicateData(request); + + await aliceWallet.populateTransactionWitnessesSignature(request); + const aliceAssetABefore = await aliceWallet.getBalance(ASSET_A); const predicateAssetABefore = await predicate.getBalance(ASSET_A); diff --git a/packages/fuel-gauge/src/predicate/predicate-arguments.test.ts b/packages/fuel-gauge/src/predicate/predicate-arguments.test.ts index 1f2bb9c8a0e..4a68edaf41a 100644 --- a/packages/fuel-gauge/src/predicate/predicate-arguments.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-arguments.test.ts @@ -1,4 +1,4 @@ -import type { WalletLocked, WalletUnlocked, BigNumberish, BN } from 'fuels'; +import type { WalletLocked, WalletUnlocked, BigNumberish } from 'fuels'; import { Provider, FUEL_NETWORK_URL, toHex, toNumber, Predicate, BaseAssetId } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtures'; @@ -29,13 +29,11 @@ describe('Predicate', () => { let wallet: WalletUnlocked; let receiver: WalletLocked; let provider: Provider; - let gasPrice: BN; const amountToReceiver = 50; - const amountToPredicate = 400_000; + const amountToPredicate = 1000; beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); - gasPrice = provider.getGasConfig().minGasPrice; }); beforeEach(async () => { @@ -55,8 +53,7 @@ describe('Predicate', () => { const initialReceiverBalance = await receiver.getBalance(); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -86,7 +83,7 @@ describe('Predicate', () => { expect(initialReceiverBalance.toHex()).toEqual(toHex(0)); await expect( - predicate.transfer(receiver.address, 50, BaseAssetId, { gasPrice: 1, gasLimit: 1000 }) + predicate.transfer(receiver.address, 50, BaseAssetId, { gasLimit: 1000 }) ).rejects.toThrow(/PredicateVerificationFailed/); }); @@ -102,8 +99,7 @@ describe('Predicate', () => { const initialReceiverBalance = await receiver.getBalance(); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -134,8 +130,7 @@ describe('Predicate', () => { await expect( predicate.transfer(receiver.address, amountToPredicate, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }) ).rejects.toThrow(/PredicateVerificationFailed/); }); @@ -163,8 +158,7 @@ describe('Predicate', () => { inputData: [{ has_account: true, total_complete: 100 }], }); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); // #endregion predicate-struct-arg @@ -198,7 +192,7 @@ describe('Predicate', () => { expect(toNumber(initialPredicateBalance)).toBeGreaterThanOrEqual(amountToPredicate); await expect( - predicate.transfer(receiver.address, 50, BaseAssetId, { gasPrice, gasLimit: 10_000 }) + predicate.transfer(receiver.address, 50, BaseAssetId, { gasLimit: 500 }) ).rejects.toThrow(/PredicateVerificationFailed/); }); @@ -214,8 +208,7 @@ describe('Predicate', () => { const initialReceiverBalance = await receiver.getBalance(); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -252,8 +245,7 @@ describe('Predicate', () => { inputData: [20, 30], }); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); // #endregion predicate-multi-args @@ -280,8 +272,7 @@ describe('Predicate', () => { const initialReceiverBalance = await receiver.getBalance(); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -309,7 +300,7 @@ describe('Predicate', () => { expect(toNumber(initialPredicateBalance)).toBeGreaterThanOrEqual(amountToPredicate); await expect( - predicate.transfer(receiver.address, 50, BaseAssetId, { gasPrice, gasLimit: 10_000 }) + predicate.transfer(receiver.address, 50, BaseAssetId, { gasLimit: 500 }) ).rejects.toThrow(/PredicateVerificationFailed/); }); }); diff --git a/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts b/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts index 33d51f9f26b..387d179e140 100644 --- a/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts @@ -1,5 +1,5 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; -import type { BN, CoinQuantityLike } from 'fuels'; +import type { CoinQuantityLike } from 'fuels'; import { getRandomB256, BaseAssetId, @@ -25,8 +25,7 @@ describe('Predicate', () => { describe('Configurables', () => { let wallet: WalletUnlocked; - let gasPrice: BN; - const amountToPredicate = 500_000; + const amountToPredicate = 2000; const defaultValues = { FEE: 10, @@ -35,7 +34,6 @@ describe('Predicate', () => { beforeEach(async () => { const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); const quantities: CoinQuantityLike[] = [ { @@ -67,8 +65,7 @@ describe('Predicate', () => { await assertBalance(destination, 0, BaseAssetId); const tx = await predicate.transfer(destination.address, amountToTransfer, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -101,8 +98,7 @@ describe('Predicate', () => { // executing predicate transfer const tx = await predicate.transfer(destination.address, amountToTransfer, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -135,8 +131,7 @@ describe('Predicate', () => { // executing predicate transfer const tx = await predicate.transfer(destination.address, amountToTransfer, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -171,8 +166,7 @@ describe('Predicate', () => { await fundPredicate(wallet, predicate, amountToPredicate); const tx = await predicate.transfer(destination.address, amountToTransfer, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -192,7 +186,7 @@ describe('Predicate', () => { }); await expect( - predicate.transfer(destination.address, 300, BaseAssetId, { gasLimit: 10_000 }) + predicate.transfer(destination.address, 300, BaseAssetId, { gasLimit: 500 }) ).rejects.toThrow(/PredicateVerificationFailed/); }); diff --git a/packages/fuel-gauge/src/predicate/predicate-estimations.test.ts b/packages/fuel-gauge/src/predicate/predicate-estimations.test.ts index 7f84830c848..03771e0c005 100644 --- a/packages/fuel-gauge/src/predicate/predicate-estimations.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-estimations.test.ts @@ -105,7 +105,6 @@ describe('Predicate', () => { amount: bn(100), assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', owner: '0xd8813d1f9ca165ce2e8710382c3d65d64e7bd43c0f7a3d51689bcdf9513411cd', - maturity: 0, type: 0, txPointer: '0x00000000000000000000000000000000', witnessIndex: 0, @@ -136,7 +135,7 @@ describe('Predicate', () => { const tx = new ScriptTransactionRequest(); await seedTestWallet(predicateTrue, [[100]]); const resources = await predicateTrue.getResourcesToSpend([[1]]); - tx.addPredicateResources(resources, predicateTrue); + tx.addResources(resources); const spy = vi.spyOn(provider.operations, 'estimatePredicates'); @@ -150,14 +149,14 @@ describe('Predicate', () => { const tx = new ScriptTransactionRequest(); await seedTestWallet(predicateTrue, [[100]]); const trueResources = await predicateTrue.getResourcesToSpend([[1]]); - tx.addPredicateResources(trueResources, predicateTrue); + tx.addResources(trueResources); const spy = vi.spyOn(provider.operations, 'estimatePredicates'); await provider.estimatePredicates(tx); await seedTestWallet(predicateStruct, [[100]]); const structResources = await predicateStruct.getResourcesToSpend([[1]]); - tx.addPredicateResources(structResources, predicateStruct); + tx.addResources(structResources); await provider.estimatePredicates(tx); @@ -168,7 +167,7 @@ describe('Predicate', () => { }); test('transferring funds from a predicate estimates the predicate and does only one dry run', async () => { - const amountToPredicate = 10_000; + const amountToPredicate = 1000; await seedTestWallet(predicateTrue, [[amountToPredicate]]); @@ -190,7 +189,7 @@ describe('Predicate', () => { const finalPredicateBalance = bn(await predicateTrue.getBalance()).toNumber(); expect(initialPredicateBalance).toBeGreaterThan(finalPredicateBalance); - expect(estimatePredicatesSpy).toHaveBeenCalledOnce(); + expect(estimatePredicatesSpy).toHaveBeenCalledTimes(1); expect(dryRunSpy).toHaveBeenCalledOnce(); }); }); diff --git a/packages/fuel-gauge/src/predicate/predicate-evaluations.test.ts b/packages/fuel-gauge/src/predicate/predicate-evaluations.test.ts index 210d7f3e3e6..881969d6d51 100644 --- a/packages/fuel-gauge/src/predicate/predicate-evaluations.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-evaluations.test.ts @@ -1,4 +1,4 @@ -import type { BN, InputValue, Provider, WalletLocked, WalletUnlocked } from 'fuels'; +import type { InputValue, Provider, WalletLocked, WalletUnlocked } from 'fuels'; import { BaseAssetId, Predicate } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtures'; @@ -22,16 +22,14 @@ describe('Predicate', () => { let wallet: WalletUnlocked; let receiver: WalletLocked; let provider: Provider; - let gasPrice: BN; beforeEach(async () => { [wallet, receiver] = await setupWallets(); provider = wallet.provider; - gasPrice = provider.getGasConfig().minGasPrice; }); it('calls a no argument predicate and returns true', async () => { - const amountToPredicate = 200_000; + const amountToPredicate = 1000; const amountToReceiver = 50; const initialReceiverBalance = await receiver.getBalance(); @@ -43,8 +41,7 @@ describe('Predicate', () => { const initialPredicateBalance = await fundPredicate(wallet, predicate, amountToPredicate); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); await tx.waitForResult(); @@ -71,8 +68,7 @@ describe('Predicate', () => { await expect( predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }) ).rejects.toThrow('PredicateVerificationFailed'); }); diff --git a/packages/fuel-gauge/src/predicate/predicate-input-data.test.ts b/packages/fuel-gauge/src/predicate/predicate-input-data.test.ts index eee56fcd52e..c06591cfc42 100644 --- a/packages/fuel-gauge/src/predicate/predicate-input-data.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-input-data.test.ts @@ -1,4 +1,4 @@ -import type { BN, InputValue, Provider, WalletLocked, WalletUnlocked } from 'fuels'; +import type { InputValue, Provider, WalletLocked, WalletUnlocked } from 'fuels'; import { BaseAssetId, Predicate } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtures'; @@ -18,16 +18,14 @@ describe('Predicate', () => { let wallet: WalletUnlocked; let receiver: WalletLocked; let provider: Provider; - let gasPrice: BN; beforeEach(async () => { [wallet, receiver] = await setupWallets(); provider = wallet.provider; - gasPrice = provider.getGasConfig().minGasPrice; }); it('throws invalid transaction when input_predicate_data is required for predicate validation', async () => { - const amountToPredicate = 200_000; + const amountToPredicate = 1000; const amountToReceiver = 50; predicate = new Predicate({ bytecode: binHexlified, @@ -40,8 +38,7 @@ describe('Predicate', () => { await expect( predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }) ).rejects.toThrow(/PredicateVerificationFailed/i); }); diff --git a/packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts b/packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts index 6d4fe063d89..2e0933f1749 100644 --- a/packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts @@ -27,7 +27,7 @@ describe('Predicate', () => { beforeAll(async () => { [wallet, receiver] = await setupWallets(); - const amountToPredicate = 10_000; + const amountToPredicate = 1000; provider = wallet.provider; predicate = new Predicate<[Validation]>({ bytecode: predicateBytesMainArgsStruct, @@ -42,7 +42,7 @@ describe('Predicate', () => { it('throws if sender does not have enough resources for tx and gas', async () => { await expect( predicate.transfer(receiver.address, predicateBalance, BaseAssetId, { - gasLimit: 10_000, + gasLimit: 100_000_000, }) ).rejects.toThrow(/not enough coins to fit the target/i); }); diff --git a/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts b/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts index b787c1eeb68..6e10507bbcc 100644 --- a/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts @@ -1,6 +1,6 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; import { expectToBeInRange } from '@fuel-ts/utils/test-utils'; -import type { BN, WalletUnlocked } from 'fuels'; +import type { WalletUnlocked } from 'fuels'; import { BaseAssetId, ContractFactory, @@ -43,10 +43,8 @@ describe('Predicate', () => { let wallet: WalletUnlocked; let receiver: WalletUnlocked; let provider: Provider; - let gasPrice: BN; beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); - gasPrice = provider.getGasConfig().minGasPrice; }); beforeEach(async () => { @@ -61,7 +59,7 @@ describe('Predicate', () => { cache: true, }); const contract = await setupContract(); - const amountToPredicate = 500_000; + const amountToPredicate = 1000; const predicate = new Predicate<[Validation]>({ bytecode: predicateBytesTrue, abi: predicateAbiMainArgsStruct, @@ -89,7 +87,7 @@ describe('Predicate', () => { tokenPoolBytes, tokenPoolAbi, wallet - ).deployContract({ gasPrice }); + ).deployContract(); const initialReceiverBalance = toNumber(await receiver.getBalance()); @@ -100,8 +98,8 @@ describe('Predicate', () => { ); // setup predicate - const amountToPredicate = 700_000; - const amountToReceiver = 200_000; + const amountToPredicate = 20_000; + const amountToReceiver = 2_000; const predicate = new Predicate<[Validation]>({ bytecode: predicateBytesStruct, provider, @@ -117,9 +115,7 @@ describe('Predicate', () => { await fundPredicate(wallet, predicate, amountToPredicate); - expect(toNumber(await predicate.getBalance())).toEqual( - initialPredicateBalance + amountToPredicate - ); + expect(toNumber(await predicate.getBalance())).toBeGreaterThan(initialPredicateBalance); // executing predicate to transfer resources to receiver const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId); diff --git a/packages/fuel-gauge/src/predicate/predicate-with-script.test.ts b/packages/fuel-gauge/src/predicate/predicate-with-script.test.ts index cf0f9ff6f57..538a3a62b46 100644 --- a/packages/fuel-gauge/src/predicate/predicate-with-script.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-with-script.test.ts @@ -1,6 +1,6 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; import { expectToBeInRange } from '@fuel-ts/utils/test-utils'; -import type { BN, BigNumberish, WalletUnlocked } from 'fuels'; +import type { BigNumberish, WalletUnlocked } from 'fuels'; import { toNumber, BaseAssetId, Script, Provider, Predicate, FUEL_NETWORK_URL } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtures'; @@ -23,13 +23,11 @@ describe('Predicate', () => { let wallet: WalletUnlocked; let receiver: WalletUnlocked; let provider: Provider; - let gasPrice: BN; beforeEach(async () => { provider = await Provider.create(FUEL_NETWORK_URL); wallet = await generateTestWallet(provider, [[5_000_000, BaseAssetId]]); receiver = await generateTestWallet(provider); - gasPrice = provider.getGasConfig().minGasPrice; }); it('calls a predicate and uses proceeds for a script call', async () => { @@ -48,8 +46,8 @@ describe('Predicate', () => { ); // setup predicate - const amountToPredicate = 500_000; - const amountToReceiver = 110_000; + const amountToPredicate = 1200; + const amountToReceiver = 100; const predicate = new Predicate<[Validation]>({ bytecode: predicateBytesStruct, provider, @@ -65,14 +63,11 @@ describe('Predicate', () => { await fundPredicate(wallet, predicate, amountToPredicate); - expect(toNumber(await predicate.getBalance())).toEqual( - initialPredicateBalance + amountToPredicate - ); + expect(toNumber(await predicate.getBalance())).toBeGreaterThan(initialPredicateBalance); // executing predicate to transfer resources to receiver const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, - gasLimit: 10_000, + gasLimit: 500, }); const { fee: predicateTxFee } = await tx.waitForResult(); diff --git a/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts b/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts index ec42d86e5ff..57c940c33c6 100644 --- a/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts +++ b/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts @@ -6,16 +6,13 @@ export const fundPredicate = async ( predicate: Predicate, amountToPredicate: BigNumberish ): Promise => { - const { minGasPrice } = wallet.provider.getGasConfig(); - - const request = new ScriptTransactionRequest({ - gasPrice: minGasPrice, - }); + const request = new ScriptTransactionRequest(); request.addCoinOutput(predicate.address, amountToPredicate, BaseAssetId); - const { minFee, requiredQuantities, gasUsed } = await wallet.provider.getTransactionCost(request); - request.gasLimit = gasUsed; - await wallet.fund(request, requiredQuantities, minFee); + const txCost = await wallet.provider.getTransactionCost(request); + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + await wallet.fund(request, txCost); await wallet.sendTransaction(request, { awaitExecution: true }); diff --git a/packages/fuel-gauge/src/predicate/utils/predicate/setupContract.ts b/packages/fuel-gauge/src/predicate/utils/predicate/setupContract.ts index ee3f56a6742..28961dd493b 100644 --- a/packages/fuel-gauge/src/predicate/utils/predicate/setupContract.ts +++ b/packages/fuel-gauge/src/predicate/utils/predicate/setupContract.ts @@ -20,8 +20,7 @@ const deployContract = async ( if (contractInstance && useCache) { return contractInstance; } - const { minGasPrice } = provider.getGasConfig(); - contractInstance = await factory.deployContract({ gasPrice: minGasPrice }); + contractInstance = await factory.deployContract(); return contractInstance; }; diff --git a/packages/fuel-gauge/src/raw-slice.test.ts b/packages/fuel-gauge/src/raw-slice.test.ts index 410925cbe4f..a838783ad90 100644 --- a/packages/fuel-gauge/src/raw-slice.test.ts +++ b/packages/fuel-gauge/src/raw-slice.test.ts @@ -27,10 +27,8 @@ const setup = async (balance = 500_000) => { const setupContract = getSetupContract('raw-slice'); let contractInstance: Contract; -let gasPrice: BN; beforeAll(async () => { contractInstance = await setupContract(); - ({ minGasPrice: gasPrice } = contractInstance.provider.getGasConfig()); }); /** @@ -92,7 +90,6 @@ describe('Raw Slice Tests', () => { // setup predicate const setupTx = await wallet.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await setupTx.waitForResult(); @@ -101,7 +98,6 @@ describe('Raw Slice Tests', () => { const initialReceiverBalance = await receiver.getBalance(); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await tx.waitForResult(); diff --git a/packages/fuel-gauge/src/revert-error.test.ts b/packages/fuel-gauge/src/revert-error.test.ts index 4f4711a6e4c..8d2d034bf8e 100644 --- a/packages/fuel-gauge/src/revert-error.test.ts +++ b/packages/fuel-gauge/src/revert-error.test.ts @@ -1,7 +1,7 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import type { BN, Contract, WalletUnlocked, TransactionResultReceipt } from 'fuels'; +import type { Contract, WalletUnlocked, TransactionResultReceipt } from 'fuels'; import { bn, ContractFactory, Provider, BaseAssetId, FUEL_NETWORK_URL, getRandomB256 } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; @@ -13,7 +13,6 @@ let wallet: WalletUnlocked; * @group node */ describe('Revert Error Testing', () => { - let gasPrice: BN; let provider: Provider; beforeAll(async () => { @@ -25,8 +24,7 @@ describe('Revert Error Testing', () => { ); const factory = new ContractFactory(bytecode, FactoryAbi, wallet); - ({ minGasPrice: gasPrice } = wallet.provider.getGasConfig()); - contractInstance = await factory.deployContract({ gasPrice }); + contractInstance = await factory.deployContract(); }); it('can pass require checks [valid]', async () => { @@ -175,7 +173,7 @@ describe('Revert Error Testing', () => { ); }); - it('should throw for "assert_ne" revert TX', async () => { + it('should throw for a missing OutputChange', async () => { const { binHexlified: tokenBytecode, abiContents: tokenAbi } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.TOKEN_CONTRACT ); @@ -194,14 +192,14 @@ describe('Revert Error Testing', () => { tokenContract.functions.mint_coins(500), tokenContract.functions.mint_to_addresses(addresses, 300), ]) - .txParams({ gasPrice }) .getTransactionRequest(); - const { gasUsed, maxFee, requiredQuantities } = await provider.getTransactionCost(request); + const txCost = await provider.getTransactionCost(request); - request.gasLimit = gasUsed; + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - await wallet.fund(request, requiredQuantities, maxFee); + await wallet.fund(request, txCost); const tx = await wallet.sendTransaction(request, { estimateTxDependencies: false, diff --git a/packages/fuel-gauge/src/script-main-args.test.ts b/packages/fuel-gauge/src/script-main-args.test.ts index fa0ad4d1e20..69e09fc749f 100644 --- a/packages/fuel-gauge/src/script-main-args.test.ts +++ b/packages/fuel-gauge/src/script-main-args.test.ts @@ -79,7 +79,6 @@ describe('Script Coverage', () => { .main(foo) .txParams({ gasLimit: 10, - gasPrice: 400, }) .call() ).rejects.toThrow(/Gas limit '10' is lower than the required/); diff --git a/packages/fuel-gauge/src/script-with-vectors.test.ts b/packages/fuel-gauge/src/script-with-vectors.test.ts index deb398b26aa..a3d0cd39872 100644 --- a/packages/fuel-gauge/src/script-with-vectors.test.ts +++ b/packages/fuel-gauge/src/script-with-vectors.test.ts @@ -41,13 +41,13 @@ describe('Script With Vectors', () => { expect(formattedLog).toEqual([ 7, 'vector.buf.ptr', - 11256, + 11232, 'vector.capacity()', 4, 'vector.len()', 4, 'addr_of vector', - 11232, + 11208, ]); }); diff --git a/packages/fuel-gauge/src/small-bytes.test.ts b/packages/fuel-gauge/src/small-bytes.test.ts index 8864dd47028..953156c88c4 100644 --- a/packages/fuel-gauge/src/small-bytes.test.ts +++ b/packages/fuel-gauge/src/small-bytes.test.ts @@ -134,9 +134,7 @@ describe('small-bytes', () => { const wallet = await createWallet(); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const { minGasPrice } = wallet.provider.getGasConfig(); const configurableContract = await factory.deployContract({ - gasPrice: minGasPrice, configurableConstants, }); @@ -159,9 +157,7 @@ describe('small-bytes', () => { const wallet = await createWallet(); const factory = new ContractFactory(binHexlified, abiContents, wallet); - const { minGasPrice } = wallet.provider.getGasConfig(); const configurableContract = await factory.deployContract({ - gasPrice: minGasPrice, configurableConstants, }); diff --git a/packages/fuel-gauge/src/std-lib-string.test.ts b/packages/fuel-gauge/src/std-lib-string.test.ts index f953e57e86f..4efb4a941a7 100644 --- a/packages/fuel-gauge/src/std-lib-string.test.ts +++ b/packages/fuel-gauge/src/std-lib-string.test.ts @@ -8,11 +8,9 @@ import { getScript, getSetupContract } from './utils'; const setupContract = getSetupContract('std-lib-string'); let contractInstance: Contract; -let gasPrice: BN; beforeAll(async () => { contractInstance = await setupContract(); - ({ minGasPrice: gasPrice } = contractInstance.provider.getGasConfig()); }); const setup = async (balance = 500_000) => { @@ -59,7 +57,6 @@ describe('std-lib-string Tests', () => { // setup predicate const setupTx = await wallet.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await setupTx.waitForResult(); @@ -67,7 +64,6 @@ describe('std-lib-string Tests', () => { const initialPredicateBalance = await predicate.getBalance(); const initialReceiverBalance = await receiver.getBalance(); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await tx.waitForResult(); diff --git a/packages/fuel-gauge/src/storage-test-contract.test.ts b/packages/fuel-gauge/src/storage-test-contract.test.ts index 5da7a7a5762..dd817cbb40b 100644 --- a/packages/fuel-gauge/src/storage-test-contract.test.ts +++ b/packages/fuel-gauge/src/storage-test-contract.test.ts @@ -1,5 +1,4 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; -import type { BN } from 'fuels'; import { toHex, Provider, ContractFactory, BaseAssetId, FUEL_NETWORK_URL } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; @@ -14,7 +13,6 @@ const setup = async () => { const provider = await Provider.create(FUEL_NETWORK_URL); // Create wallet const wallet = await generateTestWallet(provider, [[1_000_000, BaseAssetId]]); - const { minGasPrice } = wallet.provider.getGasConfig(); // Deploy contract // #region contract-deployment-storage-slots // #context import storageSlots from '../your-sway-project/out/debug/your-sway-project-storage_slots.json'; @@ -22,7 +20,6 @@ const setup = async () => { const factory = new ContractFactory(bytecode, abi, wallet); const contract = await factory.deployContract({ storageSlots, - gasPrice: minGasPrice, }); // #endregion contract-deployment-storage-slots @@ -33,11 +30,6 @@ const setup = async () => { * @group node */ describe('StorageTestContract', () => { - let gasPrice: BN; - beforeAll(async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - gasPrice = provider.getGasConfig().minGasPrice; - }); it('can increment counter', async () => { const contract = await setup(); @@ -60,7 +52,6 @@ describe('StorageTestContract', () => { const factory = new ContractFactory(bytecode, abi, wallet); // #region contract-deployment-storage-slots-inline const contract = await factory.deployContract({ - gasPrice, storageSlots: [ { key: '02dac99c283f16bc91b74f6942db7f012699a2ad51272b15207b9cc14a70dbae', diff --git a/packages/fuel-gauge/src/token-test-contract.test.ts b/packages/fuel-gauge/src/token-test-contract.test.ts index 0e8a2d856b5..a34a2c4567d 100644 --- a/packages/fuel-gauge/src/token-test-contract.test.ts +++ b/packages/fuel-gauge/src/token-test-contract.test.ts @@ -15,11 +15,10 @@ let provider: Provider; const setup = async () => { // Create wallet const wallet = await generateTestWallet(provider, [[5_000_000, BaseAssetId]]); - const { minGasPrice } = wallet.provider.getGasConfig(); // Deploy contract const factory = new ContractFactory(bytecode, abi, wallet); - const contract = await factory.deployContract({ gasPrice: minGasPrice }); + const contract = await factory.deployContract(); return contract; }; diff --git a/packages/fuel-gauge/src/transaction-response.test.ts b/packages/fuel-gauge/src/transaction-response.test.ts index 68c05837d28..4afc2650217 100644 --- a/packages/fuel-gauge/src/transaction-response.test.ts +++ b/packages/fuel-gauge/src/transaction-response.test.ts @@ -2,7 +2,6 @@ import type {} from '@fuel-ts/account/dist/providers/__generated__/operations'; import { generateTestWallet, launchNode } from '@fuel-ts/account/test-utils'; import { ErrorCode } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import type { BN } from 'fuels'; import { BaseAssetId, FUEL_NETWORK_URL, @@ -89,12 +88,10 @@ function getSubscriptionStreamFromFetch(streamHolder: { stream: ReadableStream { let provider: Provider; let adminWallet: WalletUnlocked; - let gasPrice: BN; beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); adminWallet = await generateTestWallet(provider, [[500_000]]); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); }); it('should ensure create method waits till a transaction response is given', async () => { @@ -106,7 +103,7 @@ describe('TransactionResponse', () => { destination.address, 100, BaseAssetId, - { gasPrice, gasLimit: 10_000 } + { gasLimit: 10_000 } ); const response = await TransactionResponse.create(transactionId, provider); @@ -125,7 +122,7 @@ describe('TransactionResponse', () => { destination.address, 100, BaseAssetId, - { gasPrice, gasLimit: 10_000 } + { gasLimit: 10_000 } ); const response = new TransactionResponse(transactionId, provider); @@ -172,7 +169,7 @@ describe('TransactionResponse', () => { * */ args: ['--poa-instant', 'false', '--poa-interval-period', '17sec'], }); - const nodeProvider = await Provider.create(`http://${ip}:${port}/graphql`); + const nodeProvider = await Provider.create(`http://${ip}:${port}/v1/graphql`); const genesisWallet = new WalletUnlocked( process.env.GENESIS_SECRET || randomBytes(32), @@ -185,7 +182,7 @@ describe('TransactionResponse', () => { destination.address, 100, BaseAssetId, - { gasPrice, gasLimit: 10_000 } + { gasLimit: 10_000 } ); const response = await TransactionResponse.create(transactionId, nodeProvider); @@ -216,7 +213,7 @@ describe('TransactionResponse', () => { args: ['--poa-instant', 'false', '--poa-interval-period', '2s', '--tx-pool-ttl', '1s'], loggingEnabled: false, }); - const nodeProvider = await Provider.create(`http://${ip}:${port}/graphql`); + const nodeProvider = await Provider.create(`http://${ip}:${port}/v1/graphql`); const genesisWallet = new WalletUnlocked( process.env.GENESIS_SECRET || randomBytes(32), @@ -225,9 +222,15 @@ describe('TransactionResponse', () => { const request = new ScriptTransactionRequest(); - const resources = await genesisWallet.getResourcesToSpend([[100_000]]); + request.addCoinOutput(Wallet.generate(), 100, BaseAssetId); + + const txCost = await genesisWallet.provider.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await genesisWallet.fund(request, txCost); - request.addResources(resources); request.updateWitnessByOwner( genesisWallet.address, await genesisWallet.signTransaction(request) @@ -250,7 +253,7 @@ describe('TransactionResponse', () => { args: ['--poa-instant', 'false', '--poa-interval-period', '1s', '--tx-pool-ttl', '200ms'], loggingEnabled: false, }); - const nodeProvider = await Provider.create(`http://${ip}:${port}/graphql`); + const nodeProvider = await Provider.create(`http://${ip}:${port}/v1/graphql`); const genesisWallet = new WalletUnlocked( process.env.GENESIS_SECRET || randomBytes(32), @@ -259,9 +262,17 @@ describe('TransactionResponse', () => { const request = new ScriptTransactionRequest(); - const resources = await genesisWallet.getResourcesToSpend([[100_000]]); + request.addCoinOutput(Wallet.generate(), 100, BaseAssetId); + + const txCost = await genesisWallet.provider.getTransactionCost(request, { + signatureCallback: (tx) => tx.addAccountWitnesses(genesisWallet), + }); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + await genesisWallet.fund(request, txCost); - request.addResources(resources); request.updateWitnessByOwner( genesisWallet.address, await genesisWallet.signTransaction(request) diff --git a/packages/fuel-gauge/src/transaction-summary.test.ts b/packages/fuel-gauge/src/transaction-summary.test.ts index ab147f94a7d..56df2158045 100644 --- a/packages/fuel-gauge/src/transaction-summary.test.ts +++ b/packages/fuel-gauge/src/transaction-summary.test.ts @@ -33,12 +33,10 @@ import { getSetupContract } from './utils'; describe('TransactionSummary', () => { let provider: Provider; let adminWallet: WalletUnlocked; - let gasPrice: BN; beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); adminWallet = await generateTestWallet(provider, [[100_000_000, BaseAssetId]]); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); }); const verifyTransactionSummary = (params: { @@ -71,18 +69,21 @@ describe('TransactionSummary', () => { const destination = Wallet.generate({ provider, }); + const amountToTransfer = 100; const request = new ScriptTransactionRequest({ gasLimit: 10000, - gasPrice: 1, }); request.addCoinOutput(destination.address, amountToTransfer, BaseAssetId); - const resources = await adminWallet.getResourcesToSpend([[100_000]]); + const txCost = await adminWallet.provider.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - request.addResources(resources); + await adminWallet.fund(request, txCost); const tx = await adminWallet.sendTransaction(request); @@ -107,7 +108,6 @@ describe('TransactionSummary', () => { }); const tx1 = await adminWallet.transfer(sender.address, 500_000, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); const transactionResponse1 = await tx1.waitForResult(); @@ -119,7 +119,6 @@ describe('TransactionSummary', () => { }); const tx2 = await sender.transfer(destination.address, amountToTransfer, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); const transactionResponse2 = await tx2.waitForResult(); @@ -147,12 +146,14 @@ describe('TransactionSummary', () => { it('should ensure getTransactionSummaryFromRequest executes just fine', async () => { const request = new ScriptTransactionRequest({ gasLimit: 10000, - gasPrice: 1, }); - const resources = await adminWallet.getResourcesToSpend([[100_000, BaseAssetId]]); + const txCost = await adminWallet.provider.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - request.addResources(resources); + await adminWallet.fund(request, txCost); const transactionRequest = await adminWallet.populateTransactionWitnessesSignature(request); @@ -474,13 +475,12 @@ describe('TransactionSummary', () => { }); }); - const { gasUsed, minGasPrice, maxFee, requiredQuantities } = - await provider.getTransactionCost(request, []); + const txCost = await provider.getTransactionCost(request); - request.gasLimit = gasUsed; - request.gasPrice = minGasPrice; + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - await wallet.fund(request, requiredQuantities, maxFee); + await wallet.fund(request, txCost); const tx = await wallet.sendTransaction(request); diff --git a/packages/fuel-gauge/src/utils.ts b/packages/fuel-gauge/src/utils.ts index cd6250a2fe8..80235c5c672 100644 --- a/packages/fuel-gauge/src/utils.ts +++ b/packages/fuel-gauge/src/utils.ts @@ -14,8 +14,7 @@ const deployContract = async ( if (contractInstance && useCache) { return contractInstance; } - const { minGasPrice } = provider.getGasConfig(); - contractInstance = await factory.deployContract({ gasPrice: minGasPrice }); + contractInstance = await factory.deployContract(); return contractInstance; }; diff --git a/packages/fuel-gauge/src/vector-types.test.ts b/packages/fuel-gauge/src/vector-types.test.ts index 43b06f1512c..0c89532d6d0 100644 --- a/packages/fuel-gauge/src/vector-types.test.ts +++ b/packages/fuel-gauge/src/vector-types.test.ts @@ -1,5 +1,5 @@ import { generateTestWallet } from '@fuel-ts/account/test-utils'; -import type { BN, BigNumberish } from 'fuels'; +import type { BigNumberish } from 'fuels'; import { bn, Predicate, Wallet, Address, BaseAssetId, Provider, FUEL_NETWORK_URL } from 'fuels'; import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; @@ -88,16 +88,9 @@ const setup = async (balance = 500_000) => { * @group node */ describe('Vector Types Validation', () => { - let gasPrice: BN; - const { binHexlified: predicateVectorTypes, abiContents: predicateVectorTypesAbi } = getFuelGaugeForcProject(FuelGaugeProjectsEnum.PREDICATE_VECTOR_TYPES); - beforeAll(async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - ({ minGasPrice: gasPrice } = provider.getGasConfig()); - }); - it('can use supported vector types [vector-types-contract]', async () => { const setupContract = getSetupContract('vector-types-contract'); const contractInstance = await setupContract(); @@ -169,7 +162,6 @@ describe('Vector Types Validation', () => { // setup predicate const setupTx = await wallet.transfer(predicate.address, amountToPredicate, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await setupTx.waitForResult(); @@ -178,7 +170,6 @@ describe('Vector Types Validation', () => { const initialReceiverBalance = await receiver.getBalance(); const tx = await predicate.transfer(receiver.address, amountToReceiver, BaseAssetId, { - gasPrice, gasLimit: 10_000, }); await tx.waitForResult(); diff --git a/packages/fuel-gauge/test/fixtures/forc-projects/token_abi/src/main.sw b/packages/fuel-gauge/test/fixtures/forc-projects/token_abi/src/main.sw index 941eb292856..9a025e2a77c 100644 --- a/packages/fuel-gauge/test/fixtures/forc-projects/token_abi/src/main.sw +++ b/packages/fuel-gauge/test/fixtures/forc-projects/token_abi/src/main.sw @@ -3,9 +3,9 @@ library; use std::{address::Address, asset::*, contract_id::ContractId}; pub struct TransferParams { - recipient: Recipient, - asset_id: AssetId, - amount: u64, + pub recipient: Recipient, + pub asset_id: AssetId, + pub amount: u64, } abi Token { diff --git a/packages/fuels/src/cli/commands/deploy/deployContract.ts b/packages/fuels/src/cli/commands/deploy/deployContract.ts index 5166998e895..e0f285049fd 100644 --- a/packages/fuels/src/cli/commands/deploy/deployContract.ts +++ b/packages/fuels/src/cli/commands/deploy/deployContract.ts @@ -22,14 +22,9 @@ export async function deployContract( deployConfig.storageSlots = storageSlots; } - const { minGasPrice: gasPrice } = wallet.provider.getGasConfig(); - const abi = JSON.parse(readFileSync(abiPath, 'utf-8')); const contractFactory = new ContractFactory(bytecode, abi, wallet); - // eslint-disable-next-line no-param-reassign - deployConfig.gasPrice = deployConfig.gasPrice ?? gasPrice; - const contract = await contractFactory.deployContract(deployConfig); return contract.id.toB256(); } diff --git a/packages/fuels/src/cli/commands/dev/autoStartFuelCore.test.ts b/packages/fuels/src/cli/commands/dev/autoStartFuelCore.test.ts index fc8aa161f9e..dfd659b8b59 100644 --- a/packages/fuels/src/cli/commands/dev/autoStartFuelCore.test.ts +++ b/packages/fuels/src/cli/commands/dev/autoStartFuelCore.test.ts @@ -72,7 +72,7 @@ describe('autoStartFuelCore', () => { expect(core.bindIp).toEqual('0.0.0.0'); expect(core.accessIp).toEqual('127.0.0.1'); expect(core.port).toBeGreaterThanOrEqual(4000); - expect(core.providerUrl).toMatch(/http:\/\/127\.0\.0\.1:([0-9]+)\/graphql/); + expect(core.providerUrl).toMatch(/http:\/\/127\.0\.0\.1:([0-9]+)\/v1\/graphql/); expect(core.killChildProcess).toBeTruthy(); core.killChildProcess(); @@ -91,7 +91,7 @@ describe('autoStartFuelCore', () => { expect(core.bindIp).toEqual('0.0.0.0'); expect(core.accessIp).toEqual('127.0.0.1'); expect(core.port).toBeGreaterThanOrEqual(4000); - expect(core.providerUrl).toMatch(/http:\/\/127\.0\.0\.1:([0-9]+)\/graphql/); + expect(core.providerUrl).toMatch(/http:\/\/127\.0\.0\.1:([0-9]+)\/v1\/graphql/); expect(core.killChildProcess).toBeTruthy(); core.killChildProcess(); diff --git a/packages/fuels/src/cli/commands/dev/autoStartFuelCore.ts b/packages/fuels/src/cli/commands/dev/autoStartFuelCore.ts index ef7176a79c4..4efee11a6c7 100644 --- a/packages/fuels/src/cli/commands/dev/autoStartFuelCore.ts +++ b/packages/fuels/src/cli/commands/dev/autoStartFuelCore.ts @@ -35,7 +35,7 @@ export const autoStartFuelCore = async (config: FuelsConfig) => { const port = config.fuelCorePort ?? (await getPortPromise({ port: 4000 })); - const providerUrl = `http://${accessIp}:${port}/graphql`; + const providerUrl = `http://${accessIp}:${port}/v1/graphql`; const { cleanup, chainConfigPath } = await launchNode({ args: [ diff --git a/packages/fuels/test/fixtures/fuels.config.ts b/packages/fuels/test/fixtures/fuels.config.ts index 76ff37e7267..2e201acff51 100644 --- a/packages/fuels/test/fixtures/fuels.config.ts +++ b/packages/fuels/test/fixtures/fuels.config.ts @@ -16,9 +16,7 @@ export const fuelsConfig: FuelsConfig = { scripts: [join(scriptsDir, 'script')], predicates: [join(predicatesDir, 'predicate')], output: '/output', - deployConfig: { - gasPrice: 5, - }, + deployConfig: {}, useBuiltinForc: false, useBuiltinFuelCore: false, autoStartFuelCore: true, diff --git a/packages/fuels/test/utils/mockAutoStartFuelCore.ts b/packages/fuels/test/utils/mockAutoStartFuelCore.ts index bbca5f69da9..e34adedd0a5 100644 --- a/packages/fuels/test/utils/mockAutoStartFuelCore.ts +++ b/packages/fuels/test/utils/mockAutoStartFuelCore.ts @@ -1,3 +1,4 @@ +import { FUEL_NETWORK_URL } from '@fuel-ts/account/configs'; import type { SpyInstance } from 'vitest'; import * as autoStartFuelCoreMod from '../../src/cli/commands/dev/autoStartFuelCore'; @@ -13,7 +14,7 @@ export const mockStartFuelCore = (): { bindIp: '0.0.0.0', accessIp: '127.0.0.1', port: 4000, - providerUrl: `http://127.0.0.1:4000/graphql`, + providerUrl: FUEL_NETWORK_URL, killChildProcess, chainConfigPath: '/some/path/chainConfig.json', }; diff --git a/packages/interfaces/src/index.ts b/packages/interfaces/src/index.ts index 718b3975110..82b66cce116 100644 --- a/packages/interfaces/src/index.ts +++ b/packages/interfaces/src/index.ts @@ -62,7 +62,7 @@ export abstract class AbstractAccount { abstract getResourcesToSpend(quantities: any[], options?: any): any; abstract sendTransaction(transactionRequest: any, options?: any): any; abstract simulateTransaction(transactionRequest: any, options?: any): any; - abstract fund(transactionRequest: any, quantities: any, fee: any): Promise; + abstract fund(transactionRequest: any, txCost: any): Promise; } /** * @hidden diff --git a/packages/program/src/functions/base-invocation-scope.ts b/packages/program/src/functions/base-invocation-scope.ts index f3184996513..ac66d47a8a6 100644 --- a/packages/program/src/functions/base-invocation-scope.ts +++ b/packages/program/src/functions/base-invocation-scope.ts @@ -12,7 +12,7 @@ import type { AbstractProgram, } from '@fuel-ts/interfaces'; import type { BN, BigNumberish } from '@fuel-ts/math'; -import { bn, toNumber } from '@fuel-ts/math'; +import { bn } from '@fuel-ts/math'; import { InputType, TransactionType } from '@fuel-ts/transactions'; import * as asm from '@fuels/vm-asm'; @@ -30,7 +30,7 @@ import { InvocationCallResult, FunctionInvocationResult } from './invocation-res * @returns The contract call object. */ function createContractCall(funcScope: InvocationScopeLike, offset: number): ContractCall { - const { program, args, forward, func, callParameters } = funcScope.getCallConfig(); + const { program, args, forward, func, callParameters, externalAbis } = funcScope.getCallConfig(); const DATA_POINTER_OFFSET = funcScope.getCallConfig().func.isInputDataPointer ? POINTER_DATA_OFFSET : 0; @@ -46,6 +46,7 @@ function createContractCall(funcScope: InvocationScopeLike, offset: number): Con assetId: forward?.assetId, amount: forward?.amount, gas: callParameters?.gasLimit, + externalContractsAbis: externalAbis, }; } @@ -117,6 +118,11 @@ export class BaseInvocationScope { if (c.contractId) { this.transactionRequest.addContractInputAndOutput(c.contractId); } + if (c.externalContractsAbis) { + Object.keys(c.externalContractsAbis).forEach((contractId) => + this.transactionRequest.addContractInputAndOutput(Address.fromB256(contractId)) + ); + } }); } @@ -224,13 +230,14 @@ export class BaseInvocationScope { * @param options - Optional transaction cost options. * @returns The transaction cost details. */ - async getTransactionCost(options?: TransactionCostOptions) { + // TODO: Validate if options param is still needed + async getTransactionCost(_options?: TransactionCostOptions) { const provider = this.getProvider(); const request = await this.getTransactionRequest(); - request.gasPrice = bn(toNumber(request.gasPrice) || toNumber(options?.gasPrice || 0)); - const txCost = await provider.getTransactionCost(request, this.getRequiredCoins(), { + const txCost = await provider.getTransactionCost(request, { resourcesOwner: this.program.account as AbstractAccount, + quantitiesToContract: this.getRequiredCoins(), signatureCallback: this.addSignersCallback, }); @@ -245,39 +252,41 @@ export class BaseInvocationScope { async fundWithRequiredCoins() { const transactionRequest = await this.getTransactionRequest(); - const { - maxFee, - gasUsed, - minGasPrice, - estimatedInputs, - outputVariables, - missingContractIds, - requiredQuantities, - } = await this.getTransactionCost(); - this.setDefaultTxParams(transactionRequest, minGasPrice, gasUsed); + const txCost = await this.getTransactionCost(); + const { gasUsed, missingContractIds, outputVariables, maxFee } = txCost; + this.setDefaultTxParams(transactionRequest, gasUsed); // Clean coin inputs before add new coins to the request - this.transactionRequest.inputs = this.transactionRequest.inputs.filter( - (i) => i.type !== InputType.Coin - ); - - await this.program.account?.fund(this.transactionRequest, requiredQuantities, maxFee); - - this.transactionRequest.updatePredicateInputs(estimatedInputs); + transactionRequest.inputs = transactionRequest.inputs.filter((i) => i.type !== InputType.Coin); // Adding missing contract ids missingContractIds.forEach((contractId) => { - this.transactionRequest.addContractInputAndOutput(Address.fromString(contractId)); + transactionRequest.addContractInputAndOutput(Address.fromString(contractId)); }); // Adding required number of OutputVariables - this.transactionRequest.addVariableOutputs(outputVariables); + transactionRequest.addVariableOutputs(outputVariables); + + const optimizeGas = this.txParameters?.optimizeGas ?? true; + + if (this.txParameters?.gasLimit && !optimizeGas) { + transactionRequest.gasLimit = bn(this.txParameters.gasLimit); + const { maxFee: maxFeeForGasLimit } = await this.getProvider().estimateTxGasAndFee({ + transactionRequest, + }); + transactionRequest.maxFee = maxFeeForGasLimit; + } else { + transactionRequest.gasLimit = gasUsed; + transactionRequest.maxFee = maxFee; + } + + await this.program.account?.fund(transactionRequest, txCost); if (this.addSignersCallback) { - await this.addSignersCallback(this.transactionRequest); + await this.addSignersCallback(transactionRequest); } - return this; + return transactionRequest; } /** @@ -290,11 +299,8 @@ export class BaseInvocationScope { this.txParameters = txParams; const request = this.transactionRequest; - const { minGasPrice } = this.getProvider().getGasConfig(); - - request.gasPrice = bn(txParams.gasPrice || request.gasPrice || minGasPrice); + request.tip = bn(txParams.tip || request.tip); request.gasLimit = bn(txParams.gasLimit || request.gasLimit); - request.maxFee = txParams.maxFee ? bn(txParams.maxFee) : request.maxFee; request.witnessLimit = txParams.witnessLimit ? bn(txParams.witnessLimit) : request.witnessLimit; request.maturity = txParams.maturity || request.maturity; @@ -361,15 +367,12 @@ export class BaseInvocationScope { async call(): Promise> { assert(this.program.account, 'Wallet is required!'); - await this.fundWithRequiredCoins(); + const transactionRequest = await this.fundWithRequiredCoins(); - const response = await this.program.account.sendTransaction( - await this.getTransactionRequest(), - { - awaitExecution: true, - estimateTxDependencies: false, - } - ); + const response = await this.program.account.sendTransaction(transactionRequest, { + awaitExecution: true, + estimateTxDependencies: false, + }); return FunctionInvocationResult.build( this.functionInvocationScopes, @@ -393,15 +396,11 @@ export class BaseInvocationScope { 'An unlocked wallet is required to simulate a contract call.' ); } + const transactionRequest = await this.fundWithRequiredCoins(); - await this.fundWithRequiredCoins(); - - const result = await this.program.account.simulateTransaction( - await this.getTransactionRequest(), - { - estimateTxDependencies: false, - } - ); + const result = await this.program.account.simulateTransaction(transactionRequest, { + estimateTxDependencies: false, + }); return InvocationCallResult.build(this.functionInvocationScopes, result, this.isMultiCall); } @@ -459,17 +458,12 @@ export class BaseInvocationScope { } /** - * In case the gasLimit and gasPrice are *not* set by the user, this method sets some default values. + * In case the gasLimit is *not* set by the user, this method sets a default value. */ - private setDefaultTxParams( - transactionRequest: ScriptTransactionRequest, - minGasPrice: BN, - gasUsed: BN - ) { + private setDefaultTxParams(transactionRequest: ScriptTransactionRequest, gasUsed: BN) { const gasLimitSpecified = !!this.txParameters?.gasLimit || this.hasCallParamsGasLimit; - const gasPriceSpecified = !!this.txParameters?.gasPrice; - const { gasLimit, gasPrice } = transactionRequest; + const { gasLimit } = transactionRequest; if (!gasLimitSpecified) { transactionRequest.gasLimit = gasUsed; @@ -479,14 +473,5 @@ export class BaseInvocationScope { `Gas limit '${gasLimit}' is lower than the required: '${gasUsed}'.` ); } - - if (!gasPriceSpecified) { - transactionRequest.gasPrice = minGasPrice; - } else if (gasPrice.lt(minGasPrice)) { - throw new FuelError( - ErrorCode.GAS_PRICE_TOO_LOW, - `Gas price '${gasPrice}' is lower than the required: '${minGasPrice}'.` - ); - } } } diff --git a/packages/program/src/types.ts b/packages/program/src/types.ts index 72d376dcace..3f33579db47 100644 --- a/packages/program/src/types.ts +++ b/packages/program/src/types.ts @@ -18,6 +18,7 @@ export type ContractCall = { amount?: BigNumberish; assetId?: BytesLike; gas?: BigNumberish; + externalContractsAbis?: Record; }; /** @@ -33,12 +34,13 @@ export type CallParams = Partial<{ */ // #region transaction-params export type TxParams = Partial<{ - gasPrice: BigNumberish; + tip: BigNumberish; gasLimit: BigNumberish; maturity?: number; maxFee?: BigNumberish; witnessLimit?: BigNumberish; variableOutputs: number; + optimizeGas?: boolean; }>; // #endregion transaction-params @@ -92,5 +94,4 @@ export type InvocationScopeLike = { */ export type TransactionCostOptions = Partial<{ fundTransaction: boolean; - gasPrice: BigNumberish; }>; diff --git a/packages/script/src/script.test.ts b/packages/script/src/script.test.ts index 5cdec585bad..79738e28f79 100644 --- a/packages/script/src/script.test.ts +++ b/packages/script/src/script.test.ts @@ -1,12 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import type { JsonAbi } from '@fuel-ts/abi-coder'; import { Interface } from '@fuel-ts/abi-coder'; -import type { - Account, - CoinQuantityLike, - TransactionResponse, - TransactionResult, -} from '@fuel-ts/account'; +import type { Account, TransactionResponse, TransactionResult } from '@fuel-ts/account'; import { Provider, ScriptTransactionRequest } from '@fuel-ts/account'; import { FUEL_NETWORK_URL } from '@fuel-ts/account/configs'; import { generateTestWallet } from '@fuel-ts/account/test-utils'; @@ -45,24 +40,17 @@ const callScript = async ( result: TResult; response: TransactionResponse; }> => { - const { minGasPrice } = account.provider.getGasConfig(); - - const request = new ScriptTransactionRequest({ - gasLimit: 1000000, - gasPrice: minGasPrice, - }); + const request = new ScriptTransactionRequest(); request.setScript(script, data); // Keep a list of coins we need to input to this transaction - const requiredCoinQuantities: CoinQuantityLike[] = []; - requiredCoinQuantities.push({ amount: 1000, assetId: BaseAssetId }); + const txCost = await account.provider.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; - // Get and add required coins to the transaction - if (requiredCoinQuantities.length) { - const resources = await account.getResourcesToSpend(requiredCoinQuantities); - request.addResources(resources); - } + await account.fund(request, txCost); const response = await account.sendTransaction(request); const transactionResult = await response.waitForResult(); diff --git a/packages/transactions/src/coders/input.test.ts b/packages/transactions/src/coders/input.test.ts index 5cd0129b5ab..c78a753137a 100644 --- a/packages/transactions/src/coders/input.test.ts +++ b/packages/transactions/src/coders/input.test.ts @@ -27,7 +27,6 @@ describe('InputCoder', () => { txIndex: 0, }, witnessIndex: 0, - maturity: 0, predicateGasUsed: bn(0), predicateLength: 0, predicateDataLength: 0, @@ -38,7 +37,7 @@ describe('InputCoder', () => { const encoded = hexlify(new InputCoder().encode(input)); expect(encoded).toEqual( - '0x0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + '0x0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' ); const [decoded, offset] = new InputCoder().decode(arrayify(encoded), 0); @@ -60,7 +59,6 @@ describe('InputCoder', () => { txIndex: 0, }, witnessIndex: 0, - maturity: 0, predicateGasUsed: bn(0), predicateLength: MAX_U32, predicateDataLength: MAX_U32, @@ -71,7 +69,7 @@ describe('InputCoder', () => { const encoded = hexlify(new InputCoder().encode(input)); expect(encoded).toEqual( - '0x0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffff0000' + '0x0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffff0000' ); }); @@ -88,7 +86,6 @@ describe('InputCoder', () => { txIndex: 0, }, witnessIndex: 0, - maturity: 0, predicateGasUsed: bn(0), predicateLength: MAX_U32 + 1, predicateDataLength: MAX_U32 + 1, diff --git a/packages/transactions/src/coders/input.ts b/packages/transactions/src/coders/input.ts index 3eb2f7454c0..594987e1a4c 100644 --- a/packages/transactions/src/coders/input.ts +++ b/packages/transactions/src/coders/input.ts @@ -40,9 +40,6 @@ export type InputCoin = { /** Index of witness that authorizes spending the coin (u8) */ witnessIndex: number; - /** UTXO being spent must have been created at least this many blocks ago (u32) */ - maturity: number; - /** Gas used by predicate (u64) */ predicateGasUsed: BN; @@ -74,7 +71,6 @@ export class InputCoinCoder extends Coder { parts.push(new B256Coder().encode(value.assetId)); parts.push(new TxPointerCoder().encode(value.txPointer)); parts.push(new NumberCoder('u8').encode(value.witnessIndex)); - parts.push(new NumberCoder('u32').encode(value.maturity)); parts.push(new BigNumberCoder('u64').encode(value.predicateGasUsed)); parts.push(new NumberCoder('u32').encode(value.predicateLength)); parts.push(new NumberCoder('u32').encode(value.predicateDataLength)); @@ -102,8 +98,6 @@ export class InputCoinCoder extends Coder { const txPointer = decoded; [decoded, o] = new NumberCoder('u8').decode(data, o); const witnessIndex = Number(decoded); - [decoded, o] = new NumberCoder('u32').decode(data, o); - const maturity = decoded; [decoded, o] = new BigNumberCoder('u64').decode(data, o); const predicateGasUsed = decoded; [decoded, o] = new NumberCoder('u32').decode(data, o); @@ -125,7 +119,6 @@ export class InputCoinCoder extends Coder { assetId, txPointer, witnessIndex, - maturity, predicateGasUsed, predicateLength, predicateDataLength, diff --git a/packages/transactions/src/coders/policy.test.ts b/packages/transactions/src/coders/policy.test.ts index b799745a912..3eda915b208 100644 --- a/packages/transactions/src/coders/policy.test.ts +++ b/packages/transactions/src/coders/policy.test.ts @@ -11,8 +11,8 @@ import { PoliciesCoder, PolicyType } from './policy'; */ describe('PoliciesCoder', () => { describe('encode', () => { - it('should encode policy correctly (GasPrice)', () => { - const policies: Policy[] = [{ type: PolicyType.GasPrice, data: bn(57) }]; + it('should encode policy correctly (Tip)', () => { + const policies: Policy[] = [{ type: PolicyType.Tip, data: bn(57) }]; const encoded = new PoliciesCoder().encode(policies); expect(encoded).toStrictEqual(Uint8Array.from([0, 0, 0, 0, 0, 0, 0, 57])); @@ -39,9 +39,9 @@ describe('PoliciesCoder', () => { expect(encoded).toStrictEqual(Uint8Array.from([0, 0, 0, 0, 0, 0, 0, 76])); }); - it('should encode policy correctly (GasPrice + MaxFee)', () => { + it('should encode policy correctly (Tip + MaxFee)', () => { const policies: Policy[] = [ - { type: PolicyType.GasPrice, data: bn(19) }, + { type: PolicyType.Tip, data: bn(19) }, { type: PolicyType.MaxFee, data: bn(76) }, ]; const encoded = new PoliciesCoder().encode(policies); @@ -78,9 +78,9 @@ describe('PoliciesCoder', () => { ); }); - it('should encode policy correctly (GasPrice + WitnessLimit + Maturity + MaxFee)', () => { + it('should encode policy correctly (Tip + WitnessLimit + Maturity + MaxFee)', () => { const policies: Policy[] = [ - { type: PolicyType.GasPrice, data: bn(28) }, + { type: PolicyType.Tip, data: bn(28) }, { type: PolicyType.WitnessLimit, data: bn(87) }, { type: PolicyType.Maturity, data: 26 }, { type: PolicyType.MaxFee, data: bn(199) }, @@ -98,7 +98,7 @@ describe('PoliciesCoder', () => { it('should ensure unsorted policies array will not reflect in error when encoding', () => { const policies: Policy[] = [ { type: PolicyType.MaxFee, data: bn(199) }, - { type: PolicyType.GasPrice, data: bn(28) }, + { type: PolicyType.Tip, data: bn(28) }, { type: PolicyType.Maturity, data: 26 }, { type: PolicyType.WitnessLimit, data: bn(87) }, ]; @@ -116,7 +116,7 @@ describe('PoliciesCoder', () => { const policies: Policy[] = [ { type: PolicyType.MaxFee, data: bn(199) }, { type: PolicyType.MaxFee, data: bn(199) }, - { type: PolicyType.GasPrice, data: bn(28) }, + { type: PolicyType.Tip, data: bn(28) }, { type: PolicyType.Maturity, data: 26 }, { type: PolicyType.WitnessLimit, data: bn(87) }, ]; @@ -132,19 +132,19 @@ describe('PoliciesCoder', () => { }); describe('decode', () => { - it('should decode gasPrice', () => { - // gasPrice is 100 + it('should decode tip', () => { + // tip is 100 const byteArr = [0, 0, 0, 0, 0, 0, 0, 100]; const data = Uint8Array.from(byteArr); - // bitfield is 1 representing gasPrice - const policyTypes = PolicyType.GasPrice; + // bitfield is 1 representing tip + const policyTypes = PolicyType.Tip; const [policies] = new PoliciesCoder().decode(data, 0, policyTypes); expect(policies).toHaveLength(1); expect(policies[0]).toStrictEqual({ - type: PolicyType.GasPrice, + type: PolicyType.Tip, data: bn(byteArr), }); }); @@ -201,21 +201,21 @@ describe('PoliciesCoder', () => { }); it('should decode garPrice and witnessLimit', () => { - const gasPriceByteArr = [0, 0, 0, 0, 0, 0, 0, 100]; + const tipByteArr = [0, 0, 0, 0, 0, 0, 0, 100]; const witLimitByteArr = [0, 0, 0, 0, 0, 0, 11, 184]; - const data = Uint8Array.from([...gasPriceByteArr, ...witLimitByteArr]); + const data = Uint8Array.from([...tipByteArr, ...witLimitByteArr]); // bitfield is 3 representing gasLimit + witnessLimit - const policyTypes = PolicyType.GasPrice + PolicyType.WitnessLimit; + const policyTypes = PolicyType.Tip + PolicyType.WitnessLimit; expect(policyTypes).toBe(3); const [policies] = new PoliciesCoder().decode(data, 0, policyTypes); expect(policies).toHaveLength(2); expect(policies[0]).toStrictEqual({ - type: PolicyType.GasPrice, - data: bn(gasPriceByteArr), + type: PolicyType.Tip, + data: bn(tipByteArr), }); expect(policies[1]).toStrictEqual({ type: PolicyType.WitnessLimit, @@ -270,13 +270,13 @@ describe('PoliciesCoder', () => { }); it('should decode when all policy types are present', () => { - const gasPriceByteArr = [0, 0, 0, 0, 0, 0, 0, 100]; + const tipByteArr = [0, 0, 0, 0, 0, 0, 0, 100]; const witLimitByteArr = [0, 0, 0, 0, 0, 0, 11, 184]; const maturityByteArr = [0, 0, 0, 0, 0, 0, 0, 25]; const maxFeeByteArr = [0, 0, 0, 0, 0, 0, 1, 244]; const data = Uint8Array.from([ - ...gasPriceByteArr, + ...tipByteArr, ...witLimitByteArr, ...maturityByteArr, ...maxFeeByteArr, @@ -284,7 +284,7 @@ describe('PoliciesCoder', () => { // bitfield is 15 representing witnessLimit + maxFee const policyTypes = - PolicyType.GasPrice + PolicyType.WitnessLimit + PolicyType.Maturity + PolicyType.MaxFee; + PolicyType.Tip + PolicyType.WitnessLimit + PolicyType.Maturity + PolicyType.MaxFee; expect(policyTypes).toBe(15); const [policies] = new PoliciesCoder().decode(data, 0, policyTypes); @@ -292,8 +292,8 @@ describe('PoliciesCoder', () => { expect(policies).toHaveLength(4); expect(policies).toStrictEqual([ { - type: PolicyType.GasPrice, - data: bn(gasPriceByteArr), + type: PolicyType.Tip, + data: bn(tipByteArr), }, { type: PolicyType.WitnessLimit, diff --git a/packages/transactions/src/coders/policy.ts b/packages/transactions/src/coders/policy.ts index 594e62e1034..b7e4ae9a20e 100644 --- a/packages/transactions/src/coders/policy.ts +++ b/packages/transactions/src/coders/policy.ts @@ -5,16 +5,16 @@ import { concat } from '@fuel-ts/utils'; // Bitfield of used policy types. export enum PolicyType { - GasPrice = 1, + Tip = 1, WitnessLimit = 2, Maturity = 4, MaxFee = 8, } -export type Policy = PolicyGasPrice | PolicyWitnessLimit | PolicyMaturity | PolicyMaxFee; +export type Policy = PolicyTip | PolicyWitnessLimit | PolicyMaturity | PolicyMaxFee; -export type PolicyGasPrice = { - type: PolicyType.GasPrice; +export type PolicyTip = { + type: PolicyType.Tip; data: BN; }; @@ -64,7 +64,7 @@ export class PoliciesCoder extends Coder { sortedPolicies.forEach(({ data, type }) => { switch (type) { case PolicyType.MaxFee: - case PolicyType.GasPrice: + case PolicyType.Tip: case PolicyType.WitnessLimit: parts.push(new BigNumberCoder('u64').encode(data)); break; @@ -86,10 +86,10 @@ export class PoliciesCoder extends Coder { let o = offset; const policies: Policy[] = []; - if (policyTypes & PolicyType.GasPrice) { - const [gasPrice, nextOffset] = new BigNumberCoder('u64').decode(data, o); + if (policyTypes & PolicyType.Tip) { + const [tip, nextOffset] = new BigNumberCoder('u64').decode(data, o); o = nextOffset; - policies.push({ type: PolicyType.GasPrice, data: gasPrice }); + policies.push({ type: PolicyType.Tip, data: tip }); } if (policyTypes & PolicyType.WitnessLimit) { diff --git a/packages/transactions/src/coders/transaction.test.ts b/packages/transactions/src/coders/transaction.test.ts index 3aa0c6bb0da..553addf8973 100644 --- a/packages/transactions/src/coders/transaction.test.ts +++ b/packages/transactions/src/coders/transaction.test.ts @@ -31,7 +31,7 @@ describe('TransactionCoder', () => { script: B256, scriptData: B256, policies: [ - { type: PolicyType.GasPrice, data: bn(U32) }, + { type: PolicyType.Tip, data: bn(U32) }, { type: PolicyType.Maturity, data: U32 }, ], inputs: [], @@ -65,7 +65,7 @@ describe('TransactionCoder', () => { script: B256, scriptData: B256, policies: [ - { type: PolicyType.GasPrice, data: bn(U32) }, + { type: PolicyType.Tip, data: bn(U32) }, { type: PolicyType.WitnessLimit, data: bn(U32) }, { type: PolicyType.Maturity, data: U32 }, ], @@ -132,7 +132,7 @@ describe('TransactionCoder', () => { outputsCount: 0, witnessesCount: 0, salt: B256, - policies: [{ type: PolicyType.GasPrice, data: bn(U32) }], + policies: [{ type: PolicyType.Tip, data: bn(U32) }], storageSlots: [], inputs: [], outputs: [], @@ -163,7 +163,7 @@ describe('TransactionCoder', () => { witnessesCount: 1, salt: B256, policies: [ - { type: PolicyType.GasPrice, data: bn(U32) }, + { type: PolicyType.Tip, data: bn(U32) }, { type: PolicyType.WitnessLimit, data: bn(U32) }, { type: PolicyType.Maturity, data: U32 }, { type: PolicyType.MaxFee, data: bn(U32) }, @@ -206,7 +206,6 @@ describe('TransactionCoder', () => { txIndex: 0, }, witnessIndex: 0, - maturity: 0, predicateGasUsed: bn(0), predicateLength: 0, predicateDataLength: 0, @@ -239,7 +238,7 @@ describe('TransactionCoder', () => { const encoded = hexlify(new TransactionCoder().encode(transaction)); expect(encoded).toEqual( - '0x000000000000000100000000000000200000000000000001000000000000000f0000000000000001000000000000000300000000000000020000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000003e800000000000003e800000000000003e800000000000003e8d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000020d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b' + '0x000000000000000100000000000000200000000000000001000000000000000f0000000000000001000000000000000300000000000000020000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000003e800000000000003e800000000000003e800000000000003e8d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930bd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b00000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000000d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000020d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b' ); const [decoded, offset] = new TransactionCoder().decode(arrayify(encoded), 0); diff --git a/packages/transactions/src/configs.ts b/packages/transactions/src/configs.ts index 44aab68bbd0..4162201642e 100644 --- a/packages/transactions/src/configs.ts +++ b/packages/transactions/src/configs.ts @@ -10,22 +10,18 @@ export const MAX_WITNESSES = 16; * Ex.: transactionFee = Math.ceil( / MAX_GAS_PER_TX); */ -// TODO: set max script length const /** Maximum length of script, in instructions. */ export const MAX_SCRIPT_LENGTH = 1024 * 1024 * 1024; -// TODO: set max script length const /** Maximum length of script data, in bytes. */ export const MAX_SCRIPT_DATA_LENGTH = 1024 * 1024 * 1024; /** Maximum number of static contracts. */ export const MAX_STATIC_CONTRACTS = 255; -// TODO: set max predicate length value /** Maximum length of predicate, in instructions. */ export const MAX_PREDICATE_LENGTH = 1024 * 1024; -// TODO: set max predicate data length value /** Maximum length of predicate data, in bytes. */ export const MAX_PREDICATE_DATA_LENGTH = 1024 * 1024; diff --git a/packages/versions/src/lib/getBuiltinVersions.ts b/packages/versions/src/lib/getBuiltinVersions.ts index a39135fddab..2f9bf4eaddf 100644 --- a/packages/versions/src/lib/getBuiltinVersions.ts +++ b/packages/versions/src/lib/getBuiltinVersions.ts @@ -1,7 +1,7 @@ export function getBuiltinVersions() { return { - FORC: '0.49.3', - FUEL_CORE: '0.22.1', + FORC: '0.51.1', + FUEL_CORE: '0.23.0', FUELS: '0.79.0', }; } diff --git a/templates/nextjs/src/pages/predicate.tsx b/templates/nextjs/src/pages/predicate.tsx index ad0f8fed46b..d2dd775fba5 100644 --- a/templates/nextjs/src/pages/predicate.tsx +++ b/templates/nextjs/src/pages/predicate.tsx @@ -44,7 +44,6 @@ export default function PredicateExample() { } await wallet.transfer(predicate.address, amount, BaseAssetId, { - gasPrice: 1, gasLimit: 10_000, });