diff --git a/.changeset/cold-avocados-wave.md b/.changeset/cold-avocados-wave.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/cold-avocados-wave.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/gold-rice-burn.md b/.changeset/gold-rice-burn.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/gold-rice-burn.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/good-lobsters-lie.md b/.changeset/good-lobsters-lie.md new file mode 100644 index 0000000000..72e3a34dc3 --- /dev/null +++ b/.changeset/good-lobsters-lie.md @@ -0,0 +1,7 @@ +--- +"@fuel-ts/abi-typegen": minor +"@fuel-ts/abi-coder": minor +"@fuel-ts/program": patch +--- + +feat!: remove redundant exports from `v1` encoding diff --git a/.changeset/heavy-cobras-guess.md b/.changeset/heavy-cobras-guess.md new file mode 100644 index 0000000000..eaf3e7ff50 --- /dev/null +++ b/.changeset/heavy-cobras-guess.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/account": minor +--- + +chore!: rename Provider `call` to `dryRun` diff --git a/.changeset/light-paws-lie.md b/.changeset/light-paws-lie.md new file mode 100644 index 0000000000..f33abdabda --- /dev/null +++ b/.changeset/light-paws-lie.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/account": patch +--- + +chore: add test to validate mint transactions serialization diff --git a/.changeset/tasty-pens-exercise.md b/.changeset/tasty-pens-exercise.md new file mode 100644 index 0000000000..6fabdf5afe --- /dev/null +++ b/.changeset/tasty-pens-exercise.md @@ -0,0 +1,6 @@ +--- +"@fuel-ts/account": minor +"fuels": minor +--- + +fix!: updated chain assets, removed `beta-5` network diff --git a/.changeset/weak-ravens-grin.md b/.changeset/weak-ravens-grin.md new file mode 100644 index 0000000000..132a14470d --- /dev/null +++ b/.changeset/weak-ravens-grin.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/abi-coder": patch +--- + +chore: validate incorrect case key for `EnumCoder` diff --git a/.github/workflows/pr-validate-changesets.yaml b/.github/workflows/pr-validate-changesets.yaml index 497e8b9618..89097f5632 100644 --- a/.github/workflows/pr-validate-changesets.yaml +++ b/.github/workflows/pr-validate-changesets.yaml @@ -38,13 +38,13 @@ jobs: - name: Commit Changeset run: | - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config user.email "github-actions[bot]@users.noreply.github.com" git config user.name "github-actions[bot]" git add . - git commit -m "build: update dependency changeset [skip ci]" + git commit -m "build: update dependency changeset" git push origin HEAD:${{ github.event.pull_request.head.ref }} env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} validate-changeset: name: Validate PR Changeset diff --git a/.textlintrc.json b/.textlintrc.json index b43a045610..b5a8f0a6b6 100644 --- a/.textlintrc.json +++ b/.textlintrc.json @@ -11,7 +11,8 @@ "https://testnet.fuel.network/", "https://faucet-testnet.fuel.network/", "https://thebitcoinmanual.com/**", - "https://forum.fuel.network/" + "https://forum.fuel.network/", + "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date" ] } } diff --git a/apps/docs-snippets/src/guide/contracts/minted-token-asset-id.test.ts b/apps/docs-snippets/src/guide/contracts/minted-token-asset-id.test.ts new file mode 100644 index 0000000000..c2635e6751 --- /dev/null +++ b/apps/docs-snippets/src/guide/contracts/minted-token-asset-id.test.ts @@ -0,0 +1,33 @@ +import type { Contract } from 'fuels'; +import { bn, getMintedAssetId } from 'fuels'; + +import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; +import { createAndDeployContractFromProject } from '../../utils'; + +/** + * @group node + */ +describe(__filename, () => { + let contract: Contract; + + beforeAll(async () => { + contract = await createAndDeployContractFromProject(DocSnippetProjectsEnum.TOKEN); + }); + + it('should successfully execute contract call with forwarded amount', async () => { + // #region minted-token-asset-id-2 + // #import { bn, getMintedAssetId }; + + // Any valid bits256 string can be used as a sub ID + const subID = '0xc7fd1d987ada439fc085cfa3c49416cf2b504ac50151e3c2335d60595cb90745'; + const mintAmount = bn(1000); + + const txResult = await contract.functions.mint_coins(subID, mintAmount).call(); + + const mintedAssetId = getMintedAssetId(subID, contract.id.toB256()); + // #endregion minted-token-asset-id-2 + + expect(mintedAssetId).toBeDefined(); + expect(txResult.transactionResult.isStatusSuccess).toBeTruthy(); + }); +}); diff --git a/apps/docs-snippets/src/guide/cookbook/generate-fake-resources.test.ts b/apps/docs-snippets/src/guide/cookbook/generate-fake-resources.test.ts index c169a7aed3..1c03693298 100644 --- a/apps/docs-snippets/src/guide/cookbook/generate-fake-resources.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/generate-fake-resources.test.ts @@ -42,7 +42,7 @@ describe(__filename, () => { transactionRequest.addResources(resources); - const dryrunResult = await provider.call(transactionRequest); + const dryrunResult = await provider.dryRun(transactionRequest); const returnReceipt = dryrunResult.receipts.find( (receipt) => receipt.type === ReceiptType.ReturnData diff --git a/apps/docs-snippets/src/guide/types/enums.test.ts b/apps/docs-snippets/src/guide/types/enums.test.ts index ae4c3efb57..a8c2598dec 100644 --- a/apps/docs-snippets/src/guide/types/enums.test.ts +++ b/apps/docs-snippets/src/guide/types/enums.test.ts @@ -1,4 +1,5 @@ -import type { Contract } from 'fuels'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; +import { FuelError, type Contract } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; @@ -14,36 +15,71 @@ describe(__filename, () => { }); it('should successfully echo a simple enum in a contract call', async () => { - // #region enum-3 + // #region simple-enum-3 const enumVariant = 'Completed'; const { value } = await contract.functions.echo_state_error_enum(enumVariant).simulate(); expect(value).toEqual(enumVariant); - // #endregion enum-3 + // #endregion simple-enum-3 }); it('should successfully echo a enum in a contract call (UserError Enum)', async () => { - // #region enum-6 - const userErroVar = 'InsufficientPermissions'; - - const enumParam = { UserError: userErroVar }; + // #region enum-of-enums-3 + const enumParam = { UserError: 'InsufficientPermissions' }; const { value } = await contract.functions.echo_error_enum(enumParam).simulate(); expect(value).toEqual(enumParam); - // #endregion enum-6 + // #endregion enum-of-enums-3 }); it('should successfully echo a enum in a contract call (StateError Enum)', async () => { - // #region enum-7 - const stateErrorVar = 'Completed'; - - const enumParam = { StateError: stateErrorVar }; + // #region enum-of-enums-4 + const enumParam = { StateError: 'Completed' }; const { value } = await contract.functions.echo_error_enum(enumParam).simulate(); expect(value).toEqual(enumParam); - // #endregion enum-7 + // #endregion enum-of-enums-4 + }); + + it('should throw when enum value is not the correct type', async () => { + // #region enum-error-mismatch-type + // Valid types: string + const emumValue: number = 1; + + await expectToThrowFuelError( + () => contract.functions.echo_state_error_enum(emumValue).simulate(), + new FuelError(FuelError.CODES.INVALID_DECODE_VALUE, 'A field for the case must be provided.') + ); + // #endregion enum-error-mismatch-type + }); + + it('should throw when enum value is not present in Sway enum values', async () => { + // #region enum-error-value-mismatch + // Valid values: 'Void', 'Pending', 'Completed' + const emumValue = 'NotStateEnumValue'; + + await expectToThrowFuelError( + () => contract.functions.echo_state_error_enum(emumValue).simulate(), + new FuelError(FuelError.CODES.INVALID_DECODE_VALUE, 'Only one field must be provided.') + ); + // #endregion enum-error-value-mismatch + }); + + it('should throw when using incorrect key for enum of enums', async () => { + // #region enum-error-case-key-mismatch + // Valid case keys: 'StateError', 'UserError' + const enumParam = { UnknownKey: 'Completed' }; + + await expectToThrowFuelError( + () => contract.functions.echo_error_enum(enumParam).simulate(), + new FuelError( + FuelError.CODES.INVALID_DECODE_VALUE, + `Invalid case 'UnknownKey'. Valid cases: 'StateError', 'UserError'.` + ) + ); + // #endregion enum-error-case-key-mismatch }); }); diff --git a/apps/docs-snippets/src/guide/wallets/encrypting-and-decrypting-json-wallets.test.ts b/apps/docs-snippets/src/guide/wallets/encrypting-and-decrypting-json-wallets.test.ts index 0818dc4e92..2daf08a358 100644 --- a/apps/docs-snippets/src/guide/wallets/encrypting-and-decrypting-json-wallets.test.ts +++ b/apps/docs-snippets/src/guide/wallets/encrypting-and-decrypting-json-wallets.test.ts @@ -43,7 +43,7 @@ describe(__filename, () => { // #endregion encrypting-and-decrypting-json-wallets-2 expect(myBalance).toBeDefined(); - }); + }, 10000); it('should validate that fs was imported on this file', () => { /** diff --git a/apps/docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw b/apps/docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw index a0d8b24db1..33fa1f8daa 100644 --- a/apps/docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw +++ b/apps/docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw @@ -1,13 +1,13 @@ contract; -// #region enum-1 -// #region enum-4 +// #region simple-enum-1 +// #region enum-of-enums-1 pub enum StateError { Void: (), Pending: (), Completed: (), } -// #endregion enum-1 +// #endregion simple-enum-1 pub enum UserError { Unauthorized: (), @@ -18,7 +18,7 @@ pub enum Error { StateError: StateError, UserError: UserError, } -// #endregion enum-4 +// #endregion enum-of-enums-1 abi EchoEnum { fn echo_state_error_enum(state_error: StateError) -> StateError; @@ -29,18 +29,18 @@ abi EchoEnum { } impl EchoEnum for Contract { - // #region enum-2 + // #region simple-enum-2 fn echo_state_error_enum(state_error: StateError) -> StateError { state_error } - // #endregion enum-2 + // #endregion simple-enum-2 fn echo_user_error_enum(user_error: UserError) -> UserError { user_error } - // #region enum-5 + // #region enum-of-enums-2 fn echo_error_enum(error: Error) -> Error { error } - // #endregion enum-5 + // #endregion enum-of-enums-2 } diff --git a/apps/docs-snippets/test/fixtures/forc-projects/token/src/main.sw b/apps/docs-snippets/test/fixtures/forc-projects/token/src/main.sw index 013fc49489..6508420234 100644 --- a/apps/docs-snippets/test/fixtures/forc-projects/token/src/main.sw +++ b/apps/docs-snippets/test/fixtures/forc-projects/token/src/main.sw @@ -1,3 +1,4 @@ +// #region minted-token-asset-id-1 contract; use std::asset::{burn, mint, transfer}; @@ -27,3 +28,4 @@ impl Token for Contract { burn(sub_id, burn_amount); } } +// #endregion minted-token-asset-id-1 diff --git a/apps/docs/.vitepress/config.ts b/apps/docs/.vitepress/config.ts index 1c6ad0976b..fd9713a5b7 100644 --- a/apps/docs/.vitepress/config.ts +++ b/apps/docs/.vitepress/config.ts @@ -235,6 +235,10 @@ export default defineConfig({ text: 'Configurable Constants', link: '/guide/contracts/configurable-constants', }, + { + text: 'Minted Token Asset ID', + link: '/guide/contracts/minted-token-asset-id', + }, { text: 'Managing Deployed Contracts', link: '/guide/contracts/managing-deployed-contracts', diff --git a/apps/docs/src/guide/contracts/minted-token-asset-id.md b/apps/docs/src/guide/contracts/minted-token-asset-id.md new file mode 100644 index 0000000000..a97a6d0157 --- /dev/null +++ b/apps/docs/src/guide/contracts/minted-token-asset-id.md @@ -0,0 +1,20 @@ +# Minted Token Asset ID + +The asset ID of a token on the Fuel network is determined by two factors: + +- The ID of the contract that minted the token, +- A sub-identifier (Sub ID) + +> Both of which are [bits256](../types/bits256.md) strings. + +The process involves applying a SHA-256 hash algorithm to the combination of the Contract ID and the Sub ID, to derive an Asset ID - as explained [here](https://docs.fuel.network/docs/specs/identifiers/asset/#asset-id). + +Consider the following simplified token contract: + +<<< @/../../docs-snippets/test/fixtures/forc-projects/token/src/main.sw#minted-token-asset-id-1{rs:line-numbers} + +Imagine that this contract is already deployed and we are about to mint some coins: + +<<< @/../../docs-snippets/src/guide/contracts/minted-token-asset-id.test.ts#minted-token-asset-id-2{ts:line-numbers} + +Since the asset ID depends on the contract ID, which is always dynamic (unlike the sub ID, which can be set to a fixed value), the helper `getMintedAssetId` can be used to easily obtain the asset ID for a given contract ID and sub ID. diff --git a/apps/docs/src/guide/cookbook/generate-fake-resources.md b/apps/docs/src/guide/cookbook/generate-fake-resources.md index 7ceb8fd8ab..37f472ce56 100644 --- a/apps/docs/src/guide/cookbook/generate-fake-resources.md +++ b/apps/docs/src/guide/cookbook/generate-fake-resources.md @@ -6,7 +6,7 @@ Below is an example script that returns the value `1337`. You can use fake resou <<< @/../../docs-snippets/test/fixtures/forc-projects/return-script/src/main.sw#generate-fake-resources-1{rust:line-numbers} -To execute a dry-run, use the `Provider.call` method. Ensure you set the `utxo_validation` flag to true, as this script uses fake UTXOs: +To execute a dry-run, use the `Provider.dryRun` method. Ensure you set the `utxo_validation` flag to true, as this script uses fake UTXOs: <<< @/../../docs-snippets/src/guide/cookbook/generate-fake-resources.test.ts#generate-fake-resources-2{ts:line-numbers} diff --git a/apps/docs/src/guide/errors/error-codes.md b/apps/docs/src/guide/errors/error-codes.md index 63d40eb922..8e38f554f7 100644 --- a/apps/docs/src/guide/errors/error-codes.md +++ b/apps/docs/src/guide/errors/error-codes.md @@ -92,6 +92,12 @@ When the value is more than the max value. Ensure that the value is less than the max value. +## `INVALID_DECODE_VALUE` + +When you provide an incorrect value to contract, these are documented under [Enums](../types/enums.md#errors). + +Ensure that the value (and type) matches the expected format. + ## `INVALID_ENTROPY` When the entropy is not: between 16 and 32 bytes; a multiple of 4. @@ -251,4 +257,4 @@ It could be that the passphrase is incorrect and/or the wallet does _not_ exist ## `HASHER_LOCKED` The hashing algorithm is currently locked, any subsequent attempts to register a new implementation will throw this error. -The purpose of the lock function is to provide a way to ensure that the implementation of the specific hashing algorithm cannot be changed once it is locked. This can be useful in scenarios where you want to guarantee the integrity and consistency of the hashing function throughout your application. \ No newline at end of file +The purpose of the lock function is to provide a way to ensure that the implementation of the specific hashing algorithm cannot be changed once it is locked. This can be useful in scenarios where you want to guarantee the integrity and consistency of the hashing function throughout your application. diff --git a/apps/docs/src/guide/types/enums.md b/apps/docs/src/guide/types/enums.md index b9b1fba9a9..a243d4c42a 100644 --- a/apps/docs/src/guide/types/enums.md +++ b/apps/docs/src/guide/types/enums.md @@ -6,19 +6,19 @@ Sway Enums are a little distinct from TypeScript Enums. In this document, we wil Consider the following basic Sway Enum called `StateError`: -<<< @/../../docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw#enum-1{rust:line-numbers} +<<< @/../../docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw#simple-enum-1{rust:line-numbers} The type `()` indicates that there is no additional data associated with each Enum variant. Sway allows you to create Enums of Enums or associate types with Enum variants. -## Using Sway Enums As Function Parameters +### Using Sway Enums As Function Parameters Let's define a Sway contract function that takes a `StateError` Enum variant as an argument and returns it: -<<< @/../../docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw#enum-2{rust:line-numbers} +<<< @/../../docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw#simple-enum-2{rust:line-numbers} To execute the contract function and validate the response, we can use the following code: -<<< @/../../docs-snippets/src/guide/types/enums.test.ts#enum-3{ts:line-numbers} +<<< @/../../docs-snippets/src/guide/types/enums.test.ts#simple-enum-3{ts:line-numbers} In this example, we simply pass the Enum variant as a value to execute the contract function call. @@ -26,20 +26,42 @@ In this example, we simply pass the Enum variant as a value to execute the contr In this example, the `Error` Enum is an Enum of two other Enums: `StateError` and `UserError`. -<<< @/../../docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw#enum-4{rust:line-numbers} +<<< @/../../docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw#enum-of-enums-1{rust:line-numbers} -## Using Enums of Enums with Contract Functions +### Using Enums of Enums with Contract Functions Now, let's create a Sway contract function that accepts any variant of the `Error` Enum as a parameter and returns it immediately. This variant could be from either the `StateError` or `UserError` Enums. -<<< @/../../docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw#enum-5{rust:line-numbers} +<<< @/../../docs-snippets/test/fixtures/forc-projects/echo-enum/src/main.sw#enum-of-enums-2{rust:line-numbers} Since the `Error` Enum is an Enum of Enums, we need to pass the function parameter differently. The parameter will be a TypeScript object: -<<< @/../../docs-snippets/src/guide/types/enums.test.ts#enum-6{ts:line-numbers} +<<< @/../../docs-snippets/src/guide/types/enums.test.ts#enum-of-enums-3{ts:line-numbers} In this case, since the variant `InsufficientPermissions` belongs to the `UserError` Enum, we create a TypeScript object using the Enum name as the object key and the variant as the object value. We would follow the same approach if we intended to use a variant from the `StateError` Enum: -<<< @/../../docs-snippets/src/guide/types/enums.test.ts#enum-7{ts:line-numbers} +<<< @/../../docs-snippets/src/guide/types/enums.test.ts#enum-of-enums-4{ts:line-numbers} + +## Errors + +While working with enums, you may run into the following issues: + +### Using an invalid enum type + +Thrown when the type being passed to the enum does not match that expected by it. + +<<< @/../../docs-snippets/src/guide/types/enums.test.ts#enum-error-mismatch-type{ts:line-numbers} + +### Using an invalid enum value + +Thrown when the parameter passed is not an expected enum value. + +<<< @/../../docs-snippets/src/guide/types/enums.test.ts#enum-error-value-mismatch{ts:line-numbers} + +### Using an invalid enum case key + +Thrown when the passed enum case is not an expected enum case value. + +<<< @/../../docs-snippets/src/guide/types/enums.test.ts#enum-error-case-key-mismatch{ts:line-numbers} diff --git a/packages/abi-coder/src/Interface.ts b/packages/abi-coder/src/Interface.ts index d2922bf5f4..c2f9404bb6 100644 --- a/packages/abi-coder/src/Interface.ts +++ b/packages/abi-coder/src/Interface.ts @@ -49,23 +49,6 @@ export class Interface { ); } - decodeFunctionData(functionFragment: FunctionFragment | string, data: BytesLike): any { - const fragment = - typeof functionFragment === 'string' ? this.getFunction(functionFragment) : functionFragment; - - return fragment.decodeArguments(data); - } - - encodeFunctionData( - functionFragment: FunctionFragment | string, - values: Array - ): Uint8Array { - const fragment = - typeof functionFragment === 'string' ? this.getFunction(functionFragment) : functionFragment; - - return fragment.encodeArguments(values); - } - // Decode the result of a function call decodeFunctionResult(functionFragment: FunctionFragment | string, data: BytesLike): any { const fragment = diff --git a/packages/abi-coder/src/encoding/coders/EnumCoder.test.ts b/packages/abi-coder/src/encoding/coders/EnumCoder.test.ts index ffb57140ea..c8910ff4ce 100644 --- a/packages/abi-coder/src/encoding/coders/EnumCoder.test.ts +++ b/packages/abi-coder/src/encoding/coders/EnumCoder.test.ts @@ -15,69 +15,80 @@ import { EnumCoder } from './EnumCoder'; describe('EnumCoder', () => { const coder = new EnumCoder('TestEnum', { a: new BooleanCoder(), b: new BigNumberCoder('u64') }); - it('should encode an enum containing a boolean', () => { - const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 1]); - const actual = coder.encode({ a: true }); + describe('encode', () => { + it('should encode an enum containing a boolean', () => { + const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 1]); + const actual = coder.encode({ a: true }); - expect(actual).toStrictEqual(expected); - }); + expect(actual).toStrictEqual(expected); + }); - it('decodes an enum containing a boolean', () => { - const expectedValue = { a: true }; - const expectedLength = 9; - const [actualValue, actualLength] = coder.decode( - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 1]), - 0 - ); + it('should encode an enum containing a u64', () => { + const expected = new Uint8Array([ + 0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255, + ]); + const actual = coder.encode({ b: bn(U64_MAX) }); - expect(actualValue).toStrictEqual(expectedValue); - expect(actualLength).toBe(expectedLength); - }); + expect(actual).toStrictEqual(expected); + }); - it('should encode an enum containing a u64', () => { - const expected = new Uint8Array([ - 0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255, - ]); - const actual = coder.encode({ b: bn(U64_MAX) }); + it('should throw an error when encoding if no enum key is provided', async () => { + await expectToThrowFuelError( + () => coder.encode({} as never), + new FuelError(ErrorCode.INVALID_DECODE_VALUE, 'A field for the case must be provided.') + ); + }); - expect(actual).toStrictEqual(expected); + it('should throw an error when enum case key is incorrect', async () => { + await expectToThrowFuelError( + () => coder.encode({ c: 'test' } as never), + new FuelError(ErrorCode.INVALID_DECODE_VALUE, `Invalid case 'c'. Valid cases: 'a', 'b'.`) + ); + }); }); - it('decodes an enum containing a u64', () => { - const expectedValue = { b: bn(U64_MAX) }; - const expectedLength = 16; - const [actualValue, actualLength] = coder.decode( - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255]), - 0 - ); + describe('decode', () => { + it('decodes an enum containing a boolean', () => { + const expectedValue = { a: true }; + const expectedLength = 9; + const [actualValue, actualLength] = coder.decode( + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 1]), + 0 + ); - expect(actualValue).toStrictEqual(expectedValue); - expect(actualLength).toBe(expectedLength); - }); + expect(actualValue).toStrictEqual(expectedValue); + expect(actualLength).toBe(expectedLength); + }); - it('should throw an error when encoding if no enum key is provided', async () => { - await expectToThrowFuelError( - () => coder.encode({} as never), - new FuelError(ErrorCode.INVALID_DECODE_VALUE, 'A field for the case must be provided.') - ); - }); + it('decodes an enum containing a u64', () => { + const expectedValue = { b: bn(U64_MAX) }; + const expectedLength = 16; + const [actualValue, actualLength] = coder.decode( + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 255, 255, 255, 255, 255]), + 0 + ); - it('should throw an error when decoded value accesses an invalid index', async () => { - const input = new Uint8Array(Array.from(Array(8).keys())); + expect(actualValue).toStrictEqual(expectedValue); + expect(actualLength).toBe(expectedLength); + }); - await expectToThrowFuelError( - () => coder.decode(input, 0), - new FuelError( - ErrorCode.INVALID_DECODE_VALUE, - 'Invalid caseIndex "283686952306183". Valid cases: a,b.' - ) - ); - }); + it('should throw an error when decoded value accesses an invalid index', async () => { + const input = new Uint8Array(Array.from(Array(8).keys())); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError( + ErrorCode.INVALID_DECODE_VALUE, + 'Invalid caseIndex "283686952306183". Valid cases: a,b.' + ) + ); + }); - it('throws when decoding empty bytes', async () => { - await expectToThrowFuelError( - () => coder.decode(new Uint8Array(), 0), - new FuelError(ErrorCode.DECODE_ERROR, 'Invalid enum data size.') - ); + it('throws when decoding empty bytes', async () => { + await expectToThrowFuelError( + () => coder.decode(new Uint8Array(), 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid enum data size.') + ); + }); }); }); diff --git a/packages/abi-coder/src/encoding/coders/EnumCoder.ts b/packages/abi-coder/src/encoding/coders/EnumCoder.ts index f27f0d3b6e..faccf3d0cc 100644 --- a/packages/abi-coder/src/encoding/coders/EnumCoder.ts +++ b/packages/abi-coder/src/encoding/coders/EnumCoder.ts @@ -70,6 +70,16 @@ export class EnumCoder> extends Coder< } const valueCoder = this.coders[caseKey]; const caseIndex = Object.keys(this.coders).indexOf(caseKey); + if (caseIndex === -1) { + const validCases = Object.keys(this.coders) + .map((v) => `'${v}'`) + .join(', '); + throw new FuelError( + ErrorCode.INVALID_DECODE_VALUE, + `Invalid case '${caseKey}'. Valid cases: ${validCases}.` + ); + } + const encodedValue = valueCoder.encode(value[caseKey]); return new Uint8Array([...this.#caseIndexCoder.encode(caseIndex), ...encodedValue]); diff --git a/packages/abi-coder/src/index.ts b/packages/abi-coder/src/index.ts index 2c51b357a9..741fcd60b1 100644 --- a/packages/abi-coder/src/index.ts +++ b/packages/abi-coder/src/index.ts @@ -12,7 +12,6 @@ export { UTXO_ID_LEN, BYTES_32, calculateVmTxMemory, - type EncodingVersion, ENCODING_V1, } from './utils/constants'; export { AbiCoder } from './AbiCoder'; diff --git a/packages/abi-coder/test/Interface.test.ts b/packages/abi-coder/test/Interface.test.ts index d93c26ca5f..3d27d49a9f 100644 --- a/packages/abi-coder/test/Interface.test.ts +++ b/packages/abi-coder/test/Interface.test.ts @@ -102,24 +102,6 @@ describe('Abi interface', () => { it('raises an error when function is not found', () => { const fnName = 'doesnt_exist'; expect(() => exhaustiveExamplesInterface.getFunction(fnName)).toThrow(); - - expect(() => exhaustiveExamplesInterface.encodeFunctionData(fnName, [123])).toThrow(); - - expect(() => - exhaustiveExamplesInterface.decodeFunctionData(fnName, new Uint8Array()) - ).toThrow(); - }); - - it('raises an error if the arguments do not match the function input types', () => { - const values = [11, 11]; - - const errMsg = `Mismatch between provided arguments and expected ABI inputs.` - .concat(` Provided ${values.length} arguments,`) - .concat(` but expected 1 (excluding 0 optional inputs).`); - - expect(() => exhaustiveExamplesInterface.encodeFunctionData('entry_one', values)).toThrow( - errMsg - ); }); }); diff --git a/packages/abi-typegen/src/templates/contract/dts.hbs b/packages/abi-typegen/src/templates/contract/dts.hbs index 6e1e5bf4e8..c9000f005a 100644 --- a/packages/abi-typegen/src/templates/contract/dts.hbs +++ b/packages/abi-typegen/src/templates/contract/dts.hbs @@ -54,14 +54,6 @@ interface {{capitalizedName}}Interface extends Interface { {{this}}: FunctionFragment; {{/each}} }; - - {{#each encoders}} - encodeFunctionData(functionFragment: '{{functionName}}', values: [{{input}}]): Uint8Array; - {{/each}} - - {{#each decoders}} - decodeFunctionData(functionFragment: '{{functionName}}', data: BytesLike): DecodedValue; - {{/each}} } diff --git a/packages/abi-typegen/test/fixtures/templates/contract-with-configurable/dts.hbs b/packages/abi-typegen/test/fixtures/templates/contract-with-configurable/dts.hbs index 23410fcf29..158fd1a888 100644 --- a/packages/abi-typegen/test/fixtures/templates/contract-with-configurable/dts.hbs +++ b/packages/abi-typegen/test/fixtures/templates/contract-with-configurable/dts.hbs @@ -26,10 +26,6 @@ interface MyContractAbiInterface extends Interface { functions: { main: FunctionFragment; }; - - encodeFunctionData(functionFragment: 'main', values: [string, string]): Uint8Array; - - decodeFunctionData(functionFragment: 'main', data: BytesLike): DecodedValue; } export class MyContractAbi extends Contract { diff --git a/packages/abi-typegen/test/fixtures/templates/contract/dts.hbs b/packages/abi-typegen/test/fixtures/templates/contract/dts.hbs index 1fa4d62b5e..384c6e7d18 100644 --- a/packages/abi-typegen/test/fixtures/templates/contract/dts.hbs +++ b/packages/abi-typegen/test/fixtures/templates/contract/dts.hbs @@ -91,80 +91,6 @@ interface MyContractAbiInterface extends Interface { types_vector_option: FunctionFragment; types_vector_u8: FunctionFragment; }; - - encodeFunctionData(functionFragment: 'type_address', values: [AddressInput]): Uint8Array; - encodeFunctionData(functionFragment: 'type_contract_id', values: [ContractIdInput]): Uint8Array; - encodeFunctionData(functionFragment: 'type_external_enum', values: [ExternalEnumInput]): Uint8Array; - encodeFunctionData(functionFragment: 'type_external_struct', values: [ExternalStructInput]): Uint8Array; - encodeFunctionData(functionFragment: 'type_identity', values: [IdentityInput]): Uint8Array; - encodeFunctionData(functionFragment: 'types_array', values: [[BigNumberish, BigNumberish, BigNumberish]]): Uint8Array; - encodeFunctionData(functionFragment: 'types_asset_id', values: [AssetIdInput]): Uint8Array; - encodeFunctionData(functionFragment: 'types_b256', values: [string]): Uint8Array; - encodeFunctionData(functionFragment: 'types_b512', values: [string]): Uint8Array; - encodeFunctionData(functionFragment: 'types_bool', values: [boolean]): Uint8Array; - encodeFunctionData(functionFragment: 'types_bytes', values: [Bytes]): Uint8Array; - encodeFunctionData(functionFragment: 'types_empty', values: []): Uint8Array; - encodeFunctionData(functionFragment: 'types_empty_then_value', values: [BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'types_enum', values: [MyEnumInput]): Uint8Array; - encodeFunctionData(functionFragment: 'types_enum_with_vector', values: [EnumWithVectorInput]): Uint8Array; - encodeFunctionData(functionFragment: 'types_evm_address', values: [EvmAddress]): Uint8Array; - encodeFunctionData(functionFragment: 'types_generic_enum', values: [GenericEnumInput]): Uint8Array; - encodeFunctionData(functionFragment: 'types_generic_struct', values: [GenericStructWithEnumInput]): Uint8Array; - encodeFunctionData(functionFragment: 'types_option', values: [Option]): Uint8Array; - encodeFunctionData(functionFragment: 'types_option_geo', values: [Option]): Uint8Array; - encodeFunctionData(functionFragment: 'types_raw_slice', values: [RawSlice]): Uint8Array; - encodeFunctionData(functionFragment: 'types_result', values: [Result]): Uint8Array; - encodeFunctionData(functionFragment: 'types_std_string', values: [StdString]): Uint8Array; - encodeFunctionData(functionFragment: 'types_str', values: [string]): Uint8Array; - encodeFunctionData(functionFragment: 'types_struct', values: [MyStructInput]): Uint8Array; - encodeFunctionData(functionFragment: 'types_tuple', values: [[BigNumberish, BigNumberish, BigNumberish]]): Uint8Array; - encodeFunctionData(functionFragment: 'types_u16', values: [BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'types_u256', values: [BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'types_u32', values: [BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'types_u64', values: [BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'types_u8', values: [BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'types_value_then_empty', values: [BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'types_value_then_empty_then_value', values: [BigNumberish, BigNumberish]): Uint8Array; - encodeFunctionData(functionFragment: 'types_vector_geo', values: [Vec]): Uint8Array; - encodeFunctionData(functionFragment: 'types_vector_option', values: [Vec]): Uint8Array; - encodeFunctionData(functionFragment: 'types_vector_u8', values: [Vec]): Uint8Array; - - decodeFunctionData(functionFragment: 'type_address', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'type_contract_id', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'type_external_enum', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'type_external_struct', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'type_identity', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_array', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_asset_id', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_b256', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_b512', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_bool', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_bytes', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_empty', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_empty_then_value', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_enum', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_enum_with_vector', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_evm_address', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_generic_enum', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_generic_struct', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_option', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_option_geo', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_raw_slice', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_result', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_std_string', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_str', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_struct', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_tuple', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_u16', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_u256', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_u32', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_u64', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_u8', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_value_then_empty', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_value_then_empty_then_value', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_vector_geo', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_vector_option', data: BytesLike): DecodedValue; - decodeFunctionData(functionFragment: 'types_vector_u8', data: BytesLike): DecodedValue; } export class MyContractAbi extends Contract { diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index 73b7d9f368..9bdaf53fcd 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -686,7 +686,7 @@ describe('Account', () => { request.addCoinOutput(Address.fromRandom(), amount2, ASSET_A); request.addCoinOutput(Address.fromRandom(), amount3, ASSET_B); - const { dryRunStatus } = await provider.call(request, { + const { dryRunStatus } = await provider.dryRun(request, { utxoValidation: false, estimateTxDependencies: false, }); diff --git a/packages/account/src/configs.ts b/packages/account/src/configs.ts index bcf896e8be..6e4e390863 100644 --- a/packages/account/src/configs.ts +++ b/packages/account/src/configs.ts @@ -3,4 +3,5 @@ export const FUEL_NETWORK_URL: string = ? process?.env?.FUEL_NETWORK_URL || 'http://127.0.0.1:4000/v1/graphql' : 'http://127.0.0.1:4000/v1/graphql'; +export const FUEL_DEVNET_NETWORK_URL: string = 'https://devnet.fuel.network/v1/graphql'; export const FUEL_TESTNET_NETWORK_URL: string = 'https://testnet.fuel.network/v1/graphql'; diff --git a/packages/account/src/providers/assets/assets.ts b/packages/account/src/providers/assets/assets.ts index a998499d9f..154128a153 100644 --- a/packages/account/src/providers/assets/assets.ts +++ b/packages/account/src/providers/assets/assets.ts @@ -21,16 +21,16 @@ export const rawAssets: Assets = [ }, { type: 'fuel', - chainId: CHAIN_IDS.fuel.beta5, + chainId: CHAIN_IDS.fuel.devnet, decimals: 9, - assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', + assetId: '0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07', }, { type: 'fuel', - chainId: CHAIN_IDS.fuel.devnet, + chainId: CHAIN_IDS.fuel.testnet, decimals: 9, - assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, + assetId: '0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07' + } ], }, ]; diff --git a/packages/account/src/providers/assets/utils/network.test.ts b/packages/account/src/providers/assets/utils/network.test.ts index 09743e46ef..6571d03506 100644 --- a/packages/account/src/providers/assets/utils/network.test.ts +++ b/packages/account/src/providers/assets/utils/network.test.ts @@ -9,7 +9,7 @@ import { assets } from '../assets'; describe('Network Utils', () => { test('getDefaultChainId', async () => { expect(getDefaultChainId('ethereum')).toBe(11155111); - expect(getDefaultChainId('fuel')).toBe(CHAIN_IDS.fuel.devnet); + expect(getDefaultChainId('fuel')).toBe(CHAIN_IDS.fuel.testnet); }) test('getAssetWithNetwork - Ethereum', async () => { @@ -27,12 +27,12 @@ describe('Network Utils', () => { test('getAssetWithNetwork - Fuel', async () => { const asset = assets[0] as Asset - const assetFuel = getAssetWithNetwork({ asset, networkType: 'fuel', chainId: CHAIN_IDS.fuel.devnet }) + const assetFuel = getAssetWithNetwork({ asset, networkType: 'fuel', chainId: CHAIN_IDS.fuel.testnet }) expect(assetFuel).toEqual({ type: 'fuel', - chainId: CHAIN_IDS.fuel.devnet, + chainId: CHAIN_IDS.fuel.testnet, decimals: 9, - assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', + assetId: '0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07', icon: 'https://cdn.fuel.network/assets/eth.svg', name: 'Ethereum', symbol: 'ETH' @@ -64,9 +64,9 @@ describe('Network Utils', () => { expect(assetFuel).toEqual({ type: 'fuel', - chainId: CHAIN_IDS.fuel.devnet, + chainId: CHAIN_IDS.fuel.testnet, decimals: 9, - assetId: '0x0000000000000000000000000000000000000000000000000000000000000000', + assetId: '0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07', icon: 'https://cdn.fuel.network/assets/eth.svg', name: 'Ethereum', symbol: 'ETH', diff --git a/packages/account/src/providers/assets/utils/network.ts b/packages/account/src/providers/assets/utils/network.ts index 1ced33b21e..4c7fcff972 100644 --- a/packages/account/src/providers/assets/utils/network.ts +++ b/packages/account/src/providers/assets/utils/network.ts @@ -13,7 +13,7 @@ export const getDefaultChainId = (networkType: NetworkTypes): number | undefined return CHAIN_IDS.eth.sepolia; } if (networkType === 'fuel') { - return CHAIN_IDS.fuel.devnet; + return CHAIN_IDS.fuel.testnet; } return undefined; diff --git a/packages/account/src/providers/chains.ts b/packages/account/src/providers/chains.ts index d6af172b83..b2711548bd 100644 --- a/packages/account/src/providers/chains.ts +++ b/packages/account/src/providers/chains.ts @@ -4,7 +4,7 @@ export const CHAIN_IDS = { foundry: 31337, }, fuel: { - beta5: 0, - devnet: 10, + devnet: 0, + testnet: 0, }, }; diff --git a/packages/account/src/providers/operations.graphql b/packages/account/src/providers/operations.graphql index 6fbc1aebf9..558eb226f1 100644 --- a/packages/account/src/providers/operations.graphql +++ b/packages/account/src/providers/operations.graphql @@ -565,6 +565,9 @@ query getTransactions( ...transactionFragment } } + pageInfo { + ...pageInfoFragment + } } } diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 5eeaefc189..ad4af4c2e9 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -99,7 +99,7 @@ describe('Provider', () => { witnesses: ['0x'], }); - const callResult = await provider.call(transactionRequest); + const callResult = await provider.dryRun(transactionRequest); const expectedReceipts: Receipt[] = [ { diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index d032c7afcd..48aac5059e 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -34,6 +34,7 @@ import type { GqlRelayedTransactionFailed, GqlScriptParameters as ScriptParameters, GqlTxParameters as TxParameters, + GqlPageInfo, } from './__generated__/operations'; import type { Coin } from './coin'; import type { CoinQuantity, CoinQuantityLike } from './coin-quantity'; @@ -91,6 +92,11 @@ export type Block = { transactionIds: string[]; }; +export type GetTransactionsResponse = { + transactions: Transaction[]; + pageInfo: GqlPageInfo; +}; + /** * Deployed Contract bytecode and contract id */ @@ -742,7 +748,7 @@ Supported fuel-core version: ${supportedVersion}.` * @param sendTransactionParams - The provider call parameters (optional). * @returns A promise that resolves to the call result object. */ - async call( + async dryRun( transactionRequestLike: TransactionRequestLike, { utxoValidation, estimateTxDependencies = true }: ProviderCallParams = {} ): Promise { @@ -1454,6 +1460,24 @@ Supported fuel-core version: ${supportedVersion}.` )?.[0] as Transaction; } + /** + * Retrieves transactions based on the provided pagination arguments. + * @param paginationArgs - The pagination arguments for retrieving transactions. + * @returns A promise that resolves to an object containing the retrieved transactions and pagination information. + */ + async getTransactions(paginationArgs?: CursorPaginationArgs): Promise { + const { + transactions: { edges, pageInfo }, + } = await this.operations.getTransactions(paginationArgs); + + const coder = new TransactionCoder(); + const transactions = edges.map( + ({ node: { rawPayload } }) => coder.decode(arrayify(rawPayload), 0)[0] + ); + + return { transactions, pageInfo }; + } + /** * Get deployed contract with the given ID. * 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 af9faf78aa..b183d21ab3 100644 --- a/packages/account/src/providers/transaction-summary/get-transaction-summary.ts +++ b/packages/account/src/providers/transaction-summary/get-transaction-summary.ts @@ -97,7 +97,7 @@ export async function getTransactionSummaryFromRequest( ): Promise> { const { provider, transactionRequest, abiMap } = params; - const { receipts } = await provider.call(transactionRequest); + const { receipts } = await provider.dryRun(transactionRequest); const { gasPerByte, gasPriceFactor, gasCosts, maxGasPerTx } = provider.getGasConfig(); const maxInputs = provider.getChain().consensusParameters.txParameters.maxInputs; diff --git a/packages/account/src/wallet/base-wallet-unlocked.ts b/packages/account/src/wallet/base-wallet-unlocked.ts index 8100b1e381..0a344a04db 100644 --- a/packages/account/src/wallet/base-wallet-unlocked.ts +++ b/packages/account/src/wallet/base-wallet-unlocked.ts @@ -126,7 +126,7 @@ export class BaseWalletUnlocked extends Account { } /** - * Populates the witness signature for a transaction and sends a call to the network using `provider.call`. + * Populates the witness signature for a transaction and sends a call to the network using `provider.dryRun`. * * @param transactionRequestLike - The transaction request to simulate. * @returns A promise that resolves to the CallResult object. @@ -139,7 +139,7 @@ export class BaseWalletUnlocked extends Account { if (estimateTxDependencies) { await this.provider.estimateTxDependencies(transactionRequest); } - return this.provider.call( + return this.provider.dryRun( await this.populateTransactionWitnessesSignature(transactionRequest), { utxoValidation: true, diff --git a/packages/account/src/wallet/wallet-unlocked.test.ts b/packages/account/src/wallet/wallet-unlocked.test.ts index ae2b4f9aab..88f03a6cc2 100644 --- a/packages/account/src/wallet/wallet-unlocked.test.ts +++ b/packages/account/src/wallet/wallet-unlocked.test.ts @@ -232,7 +232,7 @@ describe('WalletUnlocked', () => { ); const call = vi - .spyOn(providersMod.Provider.prototype, 'call') + .spyOn(providersMod.Provider.prototype, 'dryRun') .mockImplementation(() => Promise.resolve(callResult)); const populateTransactionWitnessesSignatureSpy = vi diff --git a/packages/fuel-gauge/src/e2e-assets.test.ts b/packages/fuel-gauge/src/e2e-assets.test.ts new file mode 100644 index 0000000000..73cc7f23b7 --- /dev/null +++ b/packages/fuel-gauge/src/e2e-assets.test.ts @@ -0,0 +1,60 @@ +/* eslint-disable no-console */ +import { + Provider, + FUEL_DEVNET_NETWORK_URL, + FUEL_TESTNET_NETWORK_URL, + assets, + CHAIN_IDS, + rawAssets, +} from 'fuels'; + +type FuelChainId = keyof typeof CHAIN_IDS.fuel; + +/** + * @group e2e + */ +describe('e2e-assets', () => { + let shouldSkip: boolean = false; + let networks: [string, Provider][] = []; + + beforeAll(async () => { + if (!process.env.CI) { + console.log('Skipping live assets compatibility test'); + shouldSkip = true; + return; + } + + networks = [ + ['devnet', await Provider.create(FUEL_DEVNET_NETWORK_URL)], + ['testnet', await Provider.create(FUEL_TESTNET_NETWORK_URL)], + ]; + }); + + it(`should have correct assets`, () => { + if (shouldSkip) { + return; + } + + for (const [chainKey, provider] of networks) { + const expected = [ + { + name: 'Ethereum', + symbol: 'ETH', + icon: expect.stringContaining('eth.svg'), + networks: expect.arrayContaining([ + { + type: 'fuel', + decimals: 9, + chainId: provider.getChainId(), + assetId: provider.getBaseAssetId(), + }, + ]), + }, + ]; + + expect(CHAIN_IDS.fuel[chainKey as FuelChainId]).toEqual(provider.getChainId()); + expect(rawAssets).toEqual(expected); + expect(assets).toEqual(expected); + } + }); +}); diff --git a/packages/fuel-gauge/src/e2e-script.test.ts b/packages/fuel-gauge/src/e2e-script.test.ts index d2b7298842..ed374e20ba 100644 --- a/packages/fuel-gauge/src/e2e-script.test.ts +++ b/packages/fuel-gauge/src/e2e-script.test.ts @@ -8,7 +8,6 @@ import { getScript } from './utils'; * @group e2e */ describe('Live Script Test', () => { - const MINT_TX_ID = '0x03299946676ddc0044a52a675dd201d3173886c998a7301262141334b6d5a29e'; const UPGRADE_TX_ID = '0xe2c03044fe708e9b112027881baf9f892e6b64a630a629998922c1cab918c094'; const UPLOAD_TX_ID = '0x94bc2a189b8211796c8fe5b9c6b67624fe97d2007e104bf1b30739944f43bd73'; @@ -57,7 +56,6 @@ describe('Live Script Test', () => { }); it.skip.each([ - ['Mint', MINT_TX_ID, TransactionType.Mint], ['Upgrade', UPGRADE_TX_ID, TransactionType.Upgrade], ['Upload', UPLOAD_TX_ID, TransactionType.Upload], ])('can query and decode a %s transaction', async (_, txId, type) => { diff --git a/packages/fuel-gauge/src/predicate/predicate-general.test.ts b/packages/fuel-gauge/src/predicate/predicate-general.test.ts index 773317b147..7eedb6452f 100644 --- a/packages/fuel-gauge/src/predicate/predicate-general.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-general.test.ts @@ -62,7 +62,7 @@ describe('Predicate', () => { request = await provider.estimatePredicates(request); - const { dryRunStatus } = await provider.call(request, { + const { dryRunStatus } = await provider.dryRun(request, { utxoValidation: false, estimateTxDependencies: false, }); diff --git a/packages/fuel-gauge/src/transaction.test.ts b/packages/fuel-gauge/src/transaction.test.ts new file mode 100644 index 0000000000..e23b872a24 --- /dev/null +++ b/packages/fuel-gauge/src/transaction.test.ts @@ -0,0 +1,24 @@ +import { sleep, Provider, TransactionType } from 'fuels'; +import { launchNode } from 'fuels/test-utils'; + +/** + * @group node + */ +describe('Transaction', () => { + it('should ensure a mint transaction can be decoded just fine', async () => { + const { cleanup, ip, port } = await launchNode({ + args: ['--poa-instant', 'false', '--poa-interval-period', '100ms'], + loggingEnabled: false, + }); + + await sleep(500); + const nodeProvider = await Provider.create(`http://${ip}:${port}/v1/graphql`); + const { + transactions: [tx], + } = await nodeProvider.getTransactions({ first: 1 }); + + expect(tx.type).toBe(TransactionType.Mint); + + cleanup(); + }); +}); diff --git a/packages/program/src/functions/base-invocation-scope.ts b/packages/program/src/functions/base-invocation-scope.ts index e86f3c07fb..5e44a223db 100644 --- a/packages/program/src/functions/base-invocation-scope.ts +++ b/packages/program/src/functions/base-invocation-scope.ts @@ -31,9 +31,7 @@ function createContractCall(funcScope: InvocationScopeLike): ContractCall { return { contractId: (program as AbstractContract).id, - fnSelector: func.selector, fnSelectorBytes: func.selectorBytes, - encoding: func.encoding, data, assetId: forward?.assetId, amount: forward?.amount, diff --git a/packages/program/src/types.ts b/packages/program/src/types.ts index 7a7eff538c..501395c4e2 100644 --- a/packages/program/src/types.ts +++ b/packages/program/src/types.ts @@ -1,4 +1,4 @@ -import type { FunctionFragment, JsonAbi, EncodingVersion } from '@fuel-ts/abi-coder'; +import type { FunctionFragment, JsonAbi } from '@fuel-ts/abi-coder'; import type { CoinQuantity, CoinQuantityLike } from '@fuel-ts/account'; import type { AbstractProgram, AbstractAddress, BytesLike } from '@fuel-ts/interfaces'; import type { BigNumberish } from '@fuel-ts/math'; @@ -11,9 +11,7 @@ import type { FunctionInvocationScope } from './functions/invocation-scope'; export type ContractCall = { contractId: AbstractAddress; data: BytesLike; - fnSelector: string; fnSelectorBytes: Uint8Array; - encoding?: EncodingVersion; amount?: BigNumberish; assetId?: BytesLike; gas?: BigNumberish;