diff --git a/.changeset/angry-crabs-float.md b/.changeset/angry-crabs-float.md new file mode 100644 index 00000000000..9a4467a080a --- /dev/null +++ b/.changeset/angry-crabs-float.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/account": patch +--- + +chore: prepend version mismatch to GraphQL errors diff --git a/.changeset/nasty-carrots-report.md b/.changeset/nasty-carrots-report.md new file mode 100644 index 00000000000..fc24ba121c6 --- /dev/null +++ b/.changeset/nasty-carrots-report.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/abi-coder": patch +--- + +fix: incorrect function coder offset usage diff --git a/.changeset/wet-goats-push.md b/.changeset/wet-goats-push.md new file mode 100644 index 00000000000..9b649cfc997 --- /dev/null +++ b/.changeset/wet-goats-push.md @@ -0,0 +1,4 @@ +--- +--- + +chore: adjust commit conventions diff --git a/.changeset/wet-radios-collect.md b/.changeset/wet-radios-collect.md new file mode 100644 index 00000000000..a493bc93821 --- /dev/null +++ b/.changeset/wet-radios-collect.md @@ -0,0 +1,4 @@ +--- +--- + +docs: favour `B256` and `B512` type references diff --git a/.github/workflows/pr-lint.yaml b/.github/workflows/pr-lint.yaml index 7601e770a80..6c5ccfb7c88 100644 --- a/.github/workflows/pr-lint.yaml +++ b/.github/workflows/pr-lint.yaml @@ -39,10 +39,10 @@ jobs: feat fix chore + test build docs ci - rc - name: Check PR title length env: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b7d90e864f5..47e456266ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -228,7 +228,6 @@ pnpm bench:node pnpm bench:node packages/my-desired-package ``` - ### CI Test During the CI process an automated end-to-end (e2e) test is executed. This test is crucial as it simulates real-world scenarios on the current test-net, ensuring that the changeset maintains the expected functionality and stability. @@ -268,11 +267,10 @@ When you create a commit we kindly ask you to follow the convention `category(scope or module): message` in your commit message while using one of the following categories: -- `feat / feature`: all changes that introduce completely new code or new +- `feat`: all changes that introduce completely new code or new features - `fix`: changes that fix a bug (ideally you will additionally reference an issue if present) -- `refactor`: any code related change that is not a fix nor a feature - `docs`: changing existing or creating new documentation (i.e. README, docs for usage of a lib or cli usage) - `build`: all changes regarding the build of the software, changes to diff --git a/apps/docs/.vitepress/config.ts b/apps/docs/.vitepress/config.ts index 3ec8a73afd3..288308581b4 100644 --- a/apps/docs/.vitepress/config.ts +++ b/apps/docs/.vitepress/config.ts @@ -496,12 +496,12 @@ export default defineConfig({ link: '/guide/types/asset-id', }, { - text: 'Bits256', - link: '/guide/types/bits256', + text: 'B256', + link: '/guide/types/b256', }, { - text: 'Bits512', - link: '/guide/types/bits512', + text: 'B512', + link: '/guide/types/b512', }, { text: 'Bytes', diff --git a/apps/docs/.vitepress/plugins/utils/extractImports.test.ts b/apps/docs/.vitepress/plugins/utils/extractImports.test.ts index f13e357a620..ebbbfca576f 100644 --- a/apps/docs/.vitepress/plugins/utils/extractImports.test.ts +++ b/apps/docs/.vitepress/plugins/utils/extractImports.test.ts @@ -108,7 +108,7 @@ describe('extractImports', () => { '// #import { AssetId };', '', 'const assetId: AssetId = {', - ' value: Bits256,', + ' value: B256,', '};', ]; const filepath = '/some/file/asset-id.test.ts'; @@ -197,7 +197,7 @@ describe('extractImports', () => { ' // #import { AssetId, Address };', '', ' const assetId: AssetId = {', - ' value: Bits256,', + ' value: B256,', ' };', ' const address: Address = new Address();', ]; diff --git a/apps/docs/src/guide/contracts/managing-deployed-contracts.md b/apps/docs/src/guide/contracts/managing-deployed-contracts.md index 4be51241b5c..f1977349357 100644 --- a/apps/docs/src/guide/contracts/managing-deployed-contracts.md +++ b/apps/docs/src/guide/contracts/managing-deployed-contracts.md @@ -6,7 +6,7 @@ To interact with a deployed contract using the SDK without redeploying it, you o The `contractId` property from the [`Contract`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_program.Contract.html) class is an instance of the [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) class. -The [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) class also provides a set of utility functions for easy manipulation and conversion between address formats along with one property; `b256Address`, which is a string encoded in [`B256`](../types/bits256.md) format. +The [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) class also provides a set of utility functions for easy manipulation and conversion between address formats along with one property; `b256Address`, which is a string encoded in [`B256`](../types/b256.md) format. When you log the `contractId` property of an instantiated Contract using `console.log`, the output appears as follows: @@ -22,10 +22,10 @@ If you have already an instantiated and deployed contract in hands you can creat <<< @./snippets/managing-deployed-contracts.ts#with-contractId{ts:line-numbers} -The previous example assumes that you have a [`Contract`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_program.Contract.html) instance at hand. However, some Fuel tools and Sway use the [`b256`](../types/bits256.md) type format, a hex-encoded string-like type, for contract IDs. +The previous example assumes that you have a [`Contract`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_program.Contract.html) instance at hand. However, some Fuel tools and Sway use the [`B256`](../types/b256.md) type format, a hex-encoded string-like type, for contract IDs. You might have this format instead, for example, if you have deployed your contract with `forc deploy`. -The process of instantiating a [`Contract`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_program.Contract.html) remains the same when using a contract ID of type `b256`: +The process of instantiating a [`Contract`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_program.Contract.html) remains the same when using a contract ID of type `B256`: <<< @./snippets/managing-deployed-contracts.ts#with-b256{ts:line-numbers} diff --git a/apps/docs/src/guide/contracts/minted-token-asset-id.md b/apps/docs/src/guide/contracts/minted-token-asset-id.md index d8bd72cc0ba..db92e0c33be 100644 --- a/apps/docs/src/guide/contracts/minted-token-asset-id.md +++ b/apps/docs/src/guide/contracts/minted-token-asset-id.md @@ -5,7 +5,7 @@ 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. +> Both of which are [B256](../types/b256.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). diff --git a/apps/docs/src/guide/contracts/snippets/utilities/minted-token-asset-id.ts b/apps/docs/src/guide/contracts/snippets/utilities/minted-token-asset-id.ts index 70ca8e96c79..237277e3224 100644 --- a/apps/docs/src/guide/contracts/snippets/utilities/minted-token-asset-id.ts +++ b/apps/docs/src/guide/contracts/snippets/utilities/minted-token-asset-id.ts @@ -10,7 +10,7 @@ const deployer = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); const deployContract = await TokenFactory.deploy(deployer); const { contract } = await deployContract.waitForResult(); -// Any valid bits256 string can be used as a sub ID +// Any valid B256 string can be used as a sub ID const subID = '0xc7fd1d987ada439fc085cfa3c49416cf2b504ac50151e3c2335d60595cb90745'; const mintAmount = bn(1000); diff --git a/apps/docs/src/guide/encoding/working-with-bytes.md b/apps/docs/src/guide/encoding/working-with-bytes.md index a11ec7a6f51..9d1f8149cbb 100644 --- a/apps/docs/src/guide/encoding/working-with-bytes.md +++ b/apps/docs/src/guide/encoding/working-with-bytes.md @@ -24,9 +24,9 @@ A fixed-length string's size is known at compile time due to the argument declar <<< @./snippets/working-with-bytes.ts#working-with-bytes-3{ts:line-numbers} -### `b256` / `b512` +### `B256` / `B512` -These are fixed-length byte arrays, with `b256` containing 256 bits and `b512` containing 512 bits. You can use them for address and signature formats. +These are fixed-length byte arrays, with `B256` containing 256 bits and `B512` containing 512 bits. You can use them for address and signature formats. <<< @./snippets/working-with-bytes.ts#working-with-bytes-4{ts:line-numbers} diff --git a/apps/docs/src/guide/predicates/send-and-spend-funds-from-predicates.md b/apps/docs/src/guide/predicates/send-and-spend-funds-from-predicates.md index 3d1352a7ba2..f30c5a5efef 100644 --- a/apps/docs/src/guide/predicates/send-and-spend-funds-from-predicates.md +++ b/apps/docs/src/guide/predicates/send-and-spend-funds-from-predicates.md @@ -10,7 +10,7 @@ Consider the following predicate: <<< @/../../docs/sway/simple-predicate/src/main.sw#send-and-spend-funds-from-predicates-1{rust:line-numbers} -This predicate accepts an address of type `b256` and compares it with a hard-coded address of the same type. If both addresses are equal, the predicate returns true, otherwise it will return false. +This predicate accepts an address of type `B256` and compares it with a hard-coded address of the same type. If both addresses are equal, the predicate returns true, otherwise it will return false. ## Interacting with the Predicate Using SDK @@ -18,7 +18,7 @@ Let's use the above predicate to validate our transaction. Once you've compiled the predicate (`forc build`), you'll obtain two important artifacts: the JSON ABI and the predicate's binary code. These are needed to instantiate a new predicate. -This is where we also pass in the predicate's data. Note that the `main` function in our predicate example requires a parameter called `input_address` of type `b256`. We will pass this parameter to the `Predicate` constructor along with the bytecode and the JSON ABI. +This is where we also pass in the predicate's data. Note that the `main` function in our predicate example requires a parameter called `input_address` of type `B256`. We will pass this parameter to the `Predicate` constructor along with the bytecode and the JSON ABI. <<< @./snippets/cookbook/transferring-assets.ts#send-and-spend-funds-from-predicates-2{ts:line-numbers} diff --git a/apps/docs/src/guide/types/address.md b/apps/docs/src/guide/types/address.md index d295ec41cd3..62b09430696 100644 --- a/apps/docs/src/guide/types/address.md +++ b/apps/docs/src/guide/types/address.md @@ -1,10 +1,10 @@ # Address -In Sway, the [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) type serves as a type-safe wrapper around the primitive `b256` type. The SDK takes a different approach and has its own abstraction for the [Address](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) type. +In Sway, the [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) type serves as a type-safe wrapper around the primitive `B256` type. The SDK takes a different approach and has its own abstraction for the [Address](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) type. ## Address Class -The [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) class also provides a set of utility functions for easy manipulation and conversion between address formats along with one property; `b256Address`, which is of the [`B256`](./bits256.md) type. +The [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) class also provides a set of utility functions for easy manipulation and conversion between address formats along with one property; `b256Address`, which is of the [`B256`](./b256.md) type. <<< @/../../../packages/address/src/address.ts#address-2{ts:line-numbers} diff --git a/apps/docs/src/guide/types/asset-id.md b/apps/docs/src/guide/types/asset-id.md index 8bf7f00249e..6aad7a9bbfb 100644 --- a/apps/docs/src/guide/types/asset-id.md +++ b/apps/docs/src/guide/types/asset-id.md @@ -1,6 +1,6 @@ # Asset ID -An Asset ID can be represented using the `AssetId` type. It's definition matches the Sway standard library type being a `Struct` wrapper around an inner `Bits256` value. +An Asset ID can be represented using the `AssetId` type. It's definition matches the Sway standard library type being a `Struct` wrapper around an inner `B256` value. <<< @./snippets/asset-id/intro.ts#full{ts:line-numbers} diff --git a/apps/docs/src/guide/types/b256.md b/apps/docs/src/guide/types/b256.md new file mode 100644 index 00000000000..a0519b1ddfd --- /dev/null +++ b/apps/docs/src/guide/types/b256.md @@ -0,0 +1,21 @@ +# `B256` + +The type `B256` in Fuel represents hashes and holds a 256-bit (32-bytes) value. The TypeScript SDK represents `B256` as a hexlified string value for portability and provides utilities to convert to `Uint8Array` when the [raw bytes](./bytes32.md) are required. + +## Generating random `B256` values + +To generate a random `B256` value, you can use the `getRandomB256()` function: + +<<< @./snippets/b256/generating-random-b256.ts#full{ts:line-numbers} + +### Converting between `B256` and `Uint8Array` + +To convert between a `B256` hexlified string and a `Uint8Array`, you can use the `arrayify` and `hexlify` functions: + +<<< @./snippets/b256/converting-between-b256-uint8.ts#full{ts:line-numbers} + +## Support from `Address` Class + +A `B256` value is also supported as part of the [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) class, providing seamless integration with other components of your application. To create an [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) instance from a b256 value, use the `Address.fromB256()` method: + +<<< @./snippets/b256/support-from-address-class.ts#full{ts:line-numbers} diff --git a/apps/docs/src/guide/types/b512.md b/apps/docs/src/guide/types/b512.md new file mode 100644 index 00000000000..f9508f6ad3b --- /dev/null +++ b/apps/docs/src/guide/types/b512.md @@ -0,0 +1,25 @@ +# B512 + +In Sway, the `B512` type is commonly used to handle public keys and signatures. This guide will explain how the `B512` type is defined in Sway, how to visualize a `B512` value using the SDK, and how to interact with a contract function that accepts a `B512` parameter. + +The `B512` type in Sway is a wrapper around two `B256` types, allowing for the representation of 64-byte values. It is defined as a struct: + +<<< @/../../docs/sway/bytecode-input/src/main.sw#b512-1{rs:line-numbers} + +## `B512` in the SDK + +In the SDK, you can visualize a `B512` value by examining a wallet's public key: + +<<< @./snippets/b512/b512-in-the-sdk.ts#snippet-1{ts:line-numbers} + +## Example: Echoing a `B512` Value in a Contract Function + +Let's consider a contract function that accepts a `B512` parameter and returns the same value: + +<<< @/../../docs/sway/echo-values/src/main.sw#b512-3{rust:line-numbers} + +To call this function and validate the returned value, follow these steps: + +<<< @./snippets/b512/echoing-a-b512.ts#snippet-1{ts:line-numbers} + +In this example, we generate a wallet, use its public key as the `B512` input, call the `echo_b512` contract function, and expect the returned value to match the original input. diff --git a/apps/docs/src/guide/types/bits256.md b/apps/docs/src/guide/types/bits256.md deleted file mode 100644 index 5cc9d26c021..00000000000 --- a/apps/docs/src/guide/types/bits256.md +++ /dev/null @@ -1,21 +0,0 @@ -# `Bits256` - -The type `b256` in Fuel represents hashes and holds a 256-bit (32-bytes) value. The TypeScript SDK represents `b256` as a hexlified string value for portability and provides utilities to convert to `Uint8Array` when the [raw bytes](./bytes32.md) are required. - -## Generating random `b256` values - -To generate a random `b256` value, you can use the `getRandomB256()` function: - -<<< @./snippets/bits256/generating-random-b256.ts#full{ts:line-numbers} - -### Converting between `b256` and `Uint8Array` - -To convert between a `b256` hexlified string and a `Uint8Array`, you can use the `arrayify` and `hexlify` functions: - -<<< @./snippets/bits256/converting-between-b256-uint8.ts#full{ts:line-numbers} - -## Support from `Address` Class - -A `b256` value is also supported as part of the [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) class, providing seamless integration with other components of your application. To create an [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) instance from a b256 value, use the `Address.fromB256()` method: - -<<< @./snippets/bits256/support-from-address-class.ts#full{ts:line-numbers} diff --git a/apps/docs/src/guide/types/bits512.md b/apps/docs/src/guide/types/bits512.md deleted file mode 100644 index f4fa8da6d1f..00000000000 --- a/apps/docs/src/guide/types/bits512.md +++ /dev/null @@ -1,25 +0,0 @@ -# Bits512 - -In Sway, the `b512` type is commonly used to handle public keys and signatures. This guide will explain how the `b512` type is defined in Sway, how to visualize a `b512` value using the SDK, and how to interact with a contract function that accepts a `b512` parameter. - -The `b512` type in Sway is a wrapper around two `b256` types, allowing for the representation of 64-byte values. It is defined as a struct: - -<<< @/../../docs/sway/bytecode-input/src/main.sw#b512-1{rs:line-numbers} - -## `b512` in the SDK - -In the SDK, you can visualize a `b512` value by examining a wallet's public key: - -<<< @./snippets/bits512/b512-in-the-sdk.ts#snippet-1{ts:line-numbers} - -## Example: Echoing a `b512` Value in a Contract Function - -Let's consider a contract function that accepts a `b512` parameter and returns the same value: - -<<< @/../../docs/sway/echo-values/src/main.sw#bits512-3{rust:line-numbers} - -To call this function and validate the returned value, follow these steps: - -<<< @./snippets/bits512/echoing-a-b512.ts#snippet-1{ts:line-numbers} - -In this example, we generate a wallet, use its public key as the `b512` input, call the `echo_b512` contract function, and expect the returned value to match the original input. diff --git a/apps/docs/src/guide/types/bytes32.md b/apps/docs/src/guide/types/bytes32.md index 580006b8ca0..ec6811d5076 100644 --- a/apps/docs/src/guide/types/bytes32.md +++ b/apps/docs/src/guide/types/bytes32.md @@ -16,4 +16,4 @@ You can use the `hexlify` function to convert a byte array to a hex string, and ## Working with b256 in Fuel -In Fuel, there is a special type called b256, which is similar to `bytes32`. Like `bytes32`, `b256` is also used to represent hashes and holds a 256-bit value. You can learn more about working with `b256` values in the [Bits256 documentation](./bits256.md). +In Fuel, there is a special type called b256, which is similar to `bytes32`. Like `bytes32`, `B256` is also used to represent hashes and holds a 256-bit value. You can learn more about working with `B256` values in the [B256 documentation](./b256.md). diff --git a/apps/docs/src/guide/types/evm-address.md b/apps/docs/src/guide/types/evm-address.md index d2bd9fd466a..9a50704093a 100644 --- a/apps/docs/src/guide/types/evm-address.md +++ b/apps/docs/src/guide/types/evm-address.md @@ -1,12 +1,12 @@ # `EvmAddress` -An Ethereum Virtual Machine (EVM) Address can be represented using the `EvmAddress` type. It's definition matches the Sway standard library type being a `Struct` wrapper around an inner `Bits256` value. +An Ethereum Virtual Machine (EVM) Address can be represented using the `EvmAddress` type. It's definition matches the Sway standard library type being a `Struct` wrapper around an inner `B256` value. <<< @./snippets/evm-address/intro.ts#snippet-1{ts:line-numbers} ## Creating an EVM Address -An EVM Address only has 20 bytes therefore the first 12 bytes of the `Bits256` value are set to 0. Within the SDK, an `Address` can be instantiated and converted to a wrapped and Sway compatible EVM Address using the `toEvmAddress()` function: +An EVM Address only has 20 bytes therefore the first 12 bytes of the `B256` value are set to 0. Within the SDK, an `Address` can be instantiated and converted to a wrapped and Sway compatible EVM Address using the `toEvmAddress()` function: <<< @./snippets/evm-address/creating-an-evm.ts#snippet-1{ts:line-numbers} diff --git a/apps/docs/src/guide/types/snippets/asset-id/intro.ts b/apps/docs/src/guide/types/snippets/asset-id/intro.ts index 38822f65c97..7747c1f4a6a 100644 --- a/apps/docs/src/guide/types/snippets/asset-id/intro.ts +++ b/apps/docs/src/guide/types/snippets/asset-id/intro.ts @@ -2,10 +2,10 @@ import type { AssetId } from 'fuels'; import { getRandomB256 } from 'fuels'; -const bits256 = getRandomB256(); +const b256 = getRandomB256(); const assetId: AssetId = { - bits: bits256, + bits: b256, }; // #endregion full console.log(assetId, 'assetId'); diff --git a/apps/docs/src/guide/types/snippets/bits256/converting-between-b256-uint8.ts b/apps/docs/src/guide/types/snippets/b256/converting-between-b256-uint8.ts similarity index 100% rename from apps/docs/src/guide/types/snippets/bits256/converting-between-b256-uint8.ts rename to apps/docs/src/guide/types/snippets/b256/converting-between-b256-uint8.ts diff --git a/apps/docs/src/guide/types/snippets/bits256/generating-random-b256.ts b/apps/docs/src/guide/types/snippets/b256/generating-random-b256.ts similarity index 100% rename from apps/docs/src/guide/types/snippets/bits256/generating-random-b256.ts rename to apps/docs/src/guide/types/snippets/b256/generating-random-b256.ts diff --git a/apps/docs/src/guide/types/snippets/bits256/support-from-address-class.ts b/apps/docs/src/guide/types/snippets/b256/support-from-address-class.ts similarity index 100% rename from apps/docs/src/guide/types/snippets/bits256/support-from-address-class.ts rename to apps/docs/src/guide/types/snippets/b256/support-from-address-class.ts diff --git a/apps/docs/src/guide/types/snippets/bits512/b512-in-the-sdk.ts b/apps/docs/src/guide/types/snippets/b512/b512-in-the-sdk.ts similarity index 100% rename from apps/docs/src/guide/types/snippets/bits512/b512-in-the-sdk.ts rename to apps/docs/src/guide/types/snippets/b512/b512-in-the-sdk.ts diff --git a/apps/docs/src/guide/types/snippets/bits512/echoing-a-b512.ts b/apps/docs/src/guide/types/snippets/b512/echoing-a-b512.ts similarity index 100% rename from apps/docs/src/guide/types/snippets/bits512/echoing-a-b512.ts rename to apps/docs/src/guide/types/snippets/b512/echoing-a-b512.ts diff --git a/apps/docs/src/guide/types/snippets/evm-address/intro.ts b/apps/docs/src/guide/types/snippets/evm-address/intro.ts index 1f5c1bbe47c..7fd08ee00f9 100644 --- a/apps/docs/src/guide/types/snippets/evm-address/intro.ts +++ b/apps/docs/src/guide/types/snippets/evm-address/intro.ts @@ -1,11 +1,11 @@ // #region snippet-1 import type { B256AddressEvm, EvmAddress } from 'fuels'; -const bits256: B256AddressEvm = +const b256: B256AddressEvm = '0x000000000000000000000000210cf886ce41952316441ae4cac35f00f0e882a6'; const evmAddress: EvmAddress = { - bits: bits256, + bits: b256, }; // #endregion snippet-1 diff --git a/apps/docs/src/guide/types/structs.md b/apps/docs/src/guide/types/structs.md index 81a2aad3934..92a497351fd 100644 --- a/apps/docs/src/guide/types/structs.md +++ b/apps/docs/src/guide/types/structs.md @@ -18,4 +18,4 @@ Please note that TypeScript does not have native support for `u8` and `u64` type Additionally, TypeScript does not support specifying string length, so just use `string` for the `name`. -In a similar way, since the type `b256` on the SDK is just an hexlified string, we use `string` as well. +In a similar way, since the type `B256` on the SDK is just an hexlified string, we use `string` as well. diff --git a/apps/docs/src/guide/utilities/address-conversion.md b/apps/docs/src/guide/utilities/address-conversion.md index dbb8d82bfd6..c9af27c0f35 100644 --- a/apps/docs/src/guide/utilities/address-conversion.md +++ b/apps/docs/src/guide/utilities/address-conversion.md @@ -2,11 +2,11 @@ Addresses and varying address formats are commonplace when interacting with decentralized applications. Furthermore, different networks may enforce different address formats. -The Fuel Network uses the [`Bits256`](../types/bits256.md) address format for its interactions, an example of which can be seen below: +The Fuel Network uses the [`B256`](../types/b256.md) address format for its interactions, an example of which can be seen below: <<< @/../../docs/src/guide/types/snippets/b256.ts#addresses-1{ts:line-numbers} -However, a hexlified [Bits256](../types/bits256.md) (hex) is another common address format; an example can be seen below: +However, a hexlified [B256](../types/b256.md) (hex) is another common address format; an example can be seen below: <<< @/../../docs/src/guide/types/snippets/evm-address/creating-an-evm.ts#snippet-2{ts:line-numbers} apps/ @@ -37,6 +37,6 @@ Similarly, the Wallet `address` property is also of type [`Address`](https://fue ## Converting an Asset ID -[Asset IDs](../types/asset-id.md) are a wrapped [b256](../types/bits256.md) value. The following example shows how to create an [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) from a `b256` type: +[Asset IDs](../types/asset-id.md) are a wrapped [`B256`](../types/b256.md) value. The following example shows how to create an [`Address`](https://fuels-ts-docs-api.vercel.app/classes/_fuel_ts_address.Address.html) from a `B256` type: <<< @./snippets/address-conversion/asset-id.ts#conversion-4{ts:line-numbers} diff --git a/apps/docs/sway/bytecode-input/src/main.sw b/apps/docs/sway/bytecode-input/src/main.sw index 72efbb2df17..1cf1a1c9459 100644 --- a/apps/docs/sway/bytecode-input/src/main.sw +++ b/apps/docs/sway/bytecode-input/src/main.sw @@ -6,7 +6,7 @@ abi MyContract { // #region b512-1 pub struct B512 { - /// The two `b256`s that make up the `B512`. + /// The two `B256`s that make up the `B512`. bits: [b256; 2], } // #endregion b512-1 diff --git a/apps/docs/sway/echo-values/src/main.sw b/apps/docs/sway/echo-values/src/main.sw index f48734129c6..653e4b76335 100644 --- a/apps/docs/sway/echo-values/src/main.sw +++ b/apps/docs/sway/echo-values/src/main.sw @@ -38,11 +38,11 @@ impl EchoValues for Contract { } // #endregion tuples-2 - // #region bits512-3 + // #region b512-3 fn echo_b512(input: B512) -> B512 { input } - // #endregion bits512-3 + // #endregion b512-3 fn echo_u64(value: u64) -> u64 { value } diff --git a/packages/abi-coder/src/FunctionFragment.ts b/packages/abi-coder/src/FunctionFragment.ts index f9c97f6a1b2..32087c21d19 100644 --- a/packages/abi-coder/src/FunctionFragment.ts +++ b/packages/abi-coder/src/FunctionFragment.ts @@ -105,11 +105,11 @@ export class FunctionFragment { const result = this.jsonFnOld.inputs.reduce( (obj: { decoded: unknown[]; offset: number }, input) => { const coder = AbiCoder.getCoder(this.jsonAbiOld, input, { encoding: this.encoding }); - const [decodedValue, decodedValueByteSize] = coder.decode(bytes, obj.offset); + const [decodedValue, decodedOffset] = coder.decode(bytes, obj.offset); return { decoded: [...obj.decoded, decodedValue], - offset: decodedValueByteSize, + offset: decodedOffset, }; }, { decoded: [], offset: 0 } diff --git a/packages/account/src/providers/fuel-graphql-subscriber.ts b/packages/account/src/providers/fuel-graphql-subscriber.ts index d0ff7a9ad42..715213f675a 100644 --- a/packages/account/src/providers/fuel-graphql-subscriber.ts +++ b/packages/account/src/providers/fuel-graphql-subscriber.ts @@ -2,6 +2,8 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { DocumentNode } from 'graphql'; import { print } from 'graphql'; +import { assertGqlResponseHasNoErrors } from './utils/handle-gql-error-message'; + type FuelGraphQLSubscriberOptions = { url: string; query: DocumentNode; @@ -10,6 +12,7 @@ type FuelGraphQLSubscriberOptions = { }; export class FuelGraphqlSubscriber implements AsyncIterator { + public static incompatibleNodeVersionMessage: string | false = false; private static textDecoder = new TextDecoder(); private constructor(private stream: ReadableStreamDefaultReader) {} @@ -50,12 +53,7 @@ export class FuelGraphqlSubscriber implements AsyncIterator { if (this.events.length > 0) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const { data, errors } = this.events.shift()!; - if (Array.isArray(errors)) { - throw new FuelError( - FuelError.CODES.INVALID_REQUEST, - errors.map((err) => err.message).join('\n\n') - ); - } + assertGqlResponseHasNoErrors(errors, FuelGraphqlSubscriber.incompatibleNodeVersionMessage); return { value: data, done: false }; } const { value, done } = await this.stream.read(); diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 5072e7226c2..590cb0274f0 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -9,8 +9,8 @@ import { InputType, OutputType, ReceiptType } from '@fuel-ts/transactions'; import { DateTime, arrayify, sleep } from '@fuel-ts/utils'; import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils'; import { versions } from '@fuel-ts/versions'; -import * as fuelTsVersionsMod from '@fuel-ts/versions'; +import { Wallet } from '..'; import { messageStatusResponse, MESSAGE_PROOF_RAW_RESPONSE, @@ -20,6 +20,7 @@ import { MOCK_TX_UNKNOWN_RAW_PAYLOAD, MOCK_TX_SCRIPT_RAW_PAYLOAD, } from '../../test/fixtures/transaction-summary'; +import { mockIncompatibleVersions } from '../../test/utils/mockIncompabileVersions'; import { setupTestProviderAndWallets, launchNode, TestMessage } from '../test-utils'; import type { Coin } from './coin'; @@ -1148,74 +1149,132 @@ describe('Provider', () => { expect(gasConfig.maxGasPerTx).toBeDefined(); }); - it('warns on difference between major client version and supported major version', async () => { - const { FUEL_CORE } = versions; - const [major, minor, patch] = FUEL_CORE.split('.'); - const majorMismatch = major === '0' ? 1 : parseInt(patch, 10) - 1; + it('Prepend a warning to an error with version mismatch [major]', async () => { + const { current, supported } = mockIncompatibleVersions({ + isMajorMismatch: true, + isMinorMismatch: false, + }); - const mock = { - isMajorSupported: false, - isMinorSupported: true, - isPatchSupported: true, - supportedVersion: `${majorMismatch}.${minor}.${patch}`, - }; + using launched = await setupTestProviderAndWallets(); + const { + provider: { url }, + } = launched; - if (mock.supportedVersion === FUEL_CORE) { - throw new Error(); - } + const provider = await new Provider(url).init(); + const sender = Wallet.generate({ provider }); + const receiver = Wallet.generate({ provider }); - const spy = vi.spyOn(fuelTsVersionsMod, 'checkFuelCoreVersionCompatibility'); - spy.mockImplementationOnce(() => mock); + await expectToThrowFuelError(() => sender.transfer(receiver.address, 1), { + code: ErrorCode.NOT_ENOUGH_FUNDS, + message: [ + `The account(s) sending the transaction don't have enough funds to cover the transaction.`, + ``, + `The Fuel Node that you are trying to connect to is using fuel-core version ${current.FUEL_CORE}.`, + `The TS SDK currently supports fuel-core version ${supported.FUEL_CORE}.`, + `Things may not work as expected.`, + ].join('\n'), + }); + }); - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + it('Prepend a warning to an error with version mismatch [minor]', async () => { + const { current, supported } = mockIncompatibleVersions({ + isMajorMismatch: false, + isMinorMismatch: true, + }); using launched = await setupTestProviderAndWallets(); - const { provider } = launched; + const { + provider: { url }, + } = launched; - await new Provider(provider.url).init(); + const provider = await new Provider(url).init(); + const sender = Wallet.generate({ provider }); + const receiver = Wallet.generate({ provider }); - expect(consoleWarnSpy).toHaveBeenCalledOnce(); - expect(consoleWarnSpy).toHaveBeenCalledWith( - `The Fuel Node that you are trying to connect to is using fuel-core version ${FUEL_CORE}, -which is not supported by the version of the TS SDK that you are using. -Things may not work as expected. -Supported fuel-core version: ${mock.supportedVersion}.` - ); + await expectToThrowFuelError(() => sender.transfer(receiver.address, 1), { + code: ErrorCode.NOT_ENOUGH_FUNDS, + message: [ + `The account(s) sending the transaction don't have enough funds to cover the transaction.`, + ``, + `The Fuel Node that you are trying to connect to is using fuel-core version ${current.FUEL_CORE}.`, + `The TS SDK currently supports fuel-core version ${supported.FUEL_CORE}.`, + `Things may not work as expected.`, + ].join('\n'), + }); }); - it('warns on difference between minor client version and supported minor version', async () => { - const { FUEL_CORE } = versions; - const [major, minor, patch] = FUEL_CORE.split('.'); - const minorMismatch = minor === '0' ? 1 : parseInt(patch, 10) - 1; + it('Prepend a warning to a subscription error with version mismatch [major]', async () => { + const { current, supported } = mockIncompatibleVersions({ + isMajorMismatch: true, + isMinorMismatch: false, + }); - const mock = { - isMajorSupported: true, - isMinorSupported: false, - isPatchSupported: true, - supportedVersion: `${major}.${minorMismatch}.${patch}`, - }; + using launched = await setupTestProviderAndWallets(); + const { provider } = launched; - if (mock.supportedVersion === FUEL_CORE) { - throw new Error(); - } + await expectToThrowFuelError( + async () => { + for await (const value of await provider.operations.statusChange({ + transactionId: 'invalid transaction id', + })) { + // shouldn't be reached and should fail if reached + expect(value).toBeFalsy(); + } + }, - const spy = vi.spyOn(fuelTsVersionsMod, 'checkFuelCoreVersionCompatibility'); - spy.mockImplementationOnce(() => mock); + { code: FuelError.CODES.INVALID_REQUEST } + ); - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const chainId = await provider.getChainId(); + const response = new TransactionResponse('invalid transaction id', provider, chainId); + + await expectToThrowFuelError(() => response.waitForResult(), { + code: FuelError.CODES.INVALID_REQUEST, + message: [ + `Failed to parse "TransactionId": Invalid character 'i' at position 0`, + ``, + `The Fuel Node that you are trying to connect to is using fuel-core version ${current.FUEL_CORE}.`, + `The TS SDK currently supports fuel-core version ${supported.FUEL_CORE}.`, + `Things may not work as expected.`, + ].join('\n'), + }); + }); + + it('Prepend a warning to a subscription error with version mismatch [minor]', async () => { + const { current, supported } = mockIncompatibleVersions({ + isMajorMismatch: false, + isMinorMismatch: true, + }); using launched = await setupTestProviderAndWallets(); const { provider } = launched; - await new Provider(provider.url).init(); + await expectToThrowFuelError( + async () => { + for await (const value of await provider.operations.statusChange({ + transactionId: 'invalid transaction id', + })) { + // shouldn't be reached and should fail if reached + expect(value).toBeFalsy(); + } + }, - expect(consoleWarnSpy).toHaveBeenCalledOnce(); - expect(consoleWarnSpy).toHaveBeenCalledWith( - `The Fuel Node that you are trying to connect to is using fuel-core version ${FUEL_CORE}, -which is not supported by the version of the TS SDK that you are using. -Things may not work as expected. -Supported fuel-core version: ${mock.supportedVersion}.` + { code: FuelError.CODES.INVALID_REQUEST } ); + + const chainId = await provider.getChainId(); + const response = new TransactionResponse('invalid transaction id', provider, chainId); + + await expectToThrowFuelError(() => response.waitForResult(), { + code: FuelError.CODES.INVALID_REQUEST, + message: [ + `Failed to parse "TransactionId": Invalid character 'i' at position 0`, + ``, + `The Fuel Node that you are trying to connect to is using fuel-core version ${current.FUEL_CORE}.`, + `The TS SDK currently supports fuel-core version ${supported.FUEL_CORE}.`, + `Things may not work as expected.`, + ].join('\n'), + }); }); it('An invalid subscription request throws a FuelError and does not hold the test runner (closes all handles)', async () => { diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index b894d9b6b89..cd8b95da0bb 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -62,7 +62,7 @@ import { } from './utils'; import type { RetryOptions } from './utils/auto-retry-fetch'; import { autoRetryFetch } from './utils/auto-retry-fetch'; -import { handleGqlErrorMessage } from './utils/handle-gql-error-message'; +import { assertGqlResponseHasNoErrors } from './utils/handle-gql-error-message'; import { validatePaginationArgs } from './utils/validate-pagination-args'; const MAX_RETRIES = 10; @@ -414,6 +414,8 @@ export default class Provider { private static chainInfoCache: ChainInfoCache = {}; /** @hidden */ private static nodeInfoCache: NodeInfoCache = {}; + /** @hidden */ + private static incompatibleNodeVersionMessage: string = ''; /** @hidden */ public consensusParametersTimestamp?: number; @@ -609,7 +611,7 @@ export default class Provider { vmBacktrace: data.nodeInfo.vmBacktrace, }; - Provider.ensureClientVersionIsSupported(nodeInfo); + Provider.setIncompatibleNodeVersionMessage(nodeInfo); chain = processGqlChain(data.chain); @@ -628,18 +630,18 @@ export default class Provider { /** * @hidden */ - private static ensureClientVersionIsSupported(nodeInfo: NodeInfo) { + private static setIncompatibleNodeVersionMessage(nodeInfo: NodeInfo) { const { isMajorSupported, isMinorSupported, supportedVersion } = checkFuelCoreVersionCompatibility(nodeInfo.nodeVersion); if (!isMajorSupported || !isMinorSupported) { - // eslint-disable-next-line no-console - console.warn( - `The Fuel Node that you are trying to connect to is using fuel-core version ${nodeInfo.nodeVersion}, -which is not supported by the version of the TS SDK that you are using. -Things may not work as expected. -Supported fuel-core version: ${supportedVersion}.` - ); + Provider.incompatibleNodeVersionMessage = [ + `The Fuel Node that you are trying to connect to is using fuel-core version ${nodeInfo.nodeVersion}.`, + `The TS SDK currently supports fuel-core version ${supportedVersion}.`, + `Things may not work as expected.`, + ].join('\n'); + FuelGraphqlSubscriber.incompatibleNodeVersionMessage = + Provider.incompatibleNodeVersionMessage; } } @@ -657,12 +659,10 @@ Supported fuel-core version: ${supportedVersion}.` responseMiddleware: (response: GraphQLClientResponse | Error) => { if ('response' in response) { const graphQlResponse = response.response as GraphQLResponse; - - if (Array.isArray(graphQlResponse?.errors)) { - for (const error of graphQlResponse.errors) { - handleGqlErrorMessage(error.message, error); - } - } + assertGqlResponseHasNoErrors( + graphQlResponse.errors, + Provider.incompatibleNodeVersionMessage + ); } }, }); diff --git a/packages/account/src/providers/utils/handle-gql-error-message.ts b/packages/account/src/providers/utils/handle-gql-error-message.ts index 3a2d3d82fb2..34c38557abd 100644 --- a/packages/account/src/providers/utils/handle-gql-error-message.ts +++ b/packages/account/src/providers/utils/handle-gql-error-message.ts @@ -6,23 +6,61 @@ export enum GqlErrorMessage { MAX_COINS_REACHED = 'max number of coins is reached while trying to fit the target', } -export const handleGqlErrorMessage = (errorMessage: string, rawError: GraphQLError) => { - switch (errorMessage) { +type GqlError = { message: string } | GraphQLError; + +const mapGqlErrorMessage = (error: GqlError): FuelError => { + switch (error.message) { case GqlErrorMessage.NOT_ENOUGH_COINS: - throw new FuelError( + return new FuelError( ErrorCode.NOT_ENOUGH_FUNDS, `The account(s) sending the transaction don't have enough funds to cover the transaction.`, {}, - rawError + error ); case GqlErrorMessage.MAX_COINS_REACHED: - throw new FuelError( + return new FuelError( ErrorCode.MAX_COINS_REACHED, 'The account retrieving coins has exceeded the maximum number of coins per asset. Please consider combining your coins into a single UTXO.', {}, - rawError + error ); default: - throw new FuelError(ErrorCode.INVALID_REQUEST, errorMessage); + return new FuelError(ErrorCode.INVALID_REQUEST, error.message, {}, error); + } +}; + +const mapGqlErrorWithIncompatibleNodeVersion = ( + error: FuelError, + incompatibleNodeVersionMessage: string | false +) => { + if (!incompatibleNodeVersionMessage) { + return error; } + + return new FuelError( + error.code, + `${error.message}\n\n${incompatibleNodeVersionMessage}`, + error.metadata, + error.rawError + ); +}; + +export const assertGqlResponseHasNoErrors = ( + errors: GqlError[] | undefined, + incompatibleNodeVersionMessage: string | false = false +) => { + if (!Array.isArray(errors)) { + return; + } + + const mappedErrors = errors.map(mapGqlErrorMessage); + if (mappedErrors.length === 1) { + throw mapGqlErrorWithIncompatibleNodeVersion(mappedErrors[0], incompatibleNodeVersionMessage); + } + + const errorMessage = mappedErrors.map((err) => err.message).join('\n'); + throw mapGqlErrorWithIncompatibleNodeVersion( + new FuelError(ErrorCode.INVALID_REQUEST, errorMessage, {}, mappedErrors), + incompatibleNodeVersionMessage + ); }; diff --git a/packages/account/test/utils/mockIncompabileVersions.ts b/packages/account/test/utils/mockIncompabileVersions.ts new file mode 100644 index 00000000000..c19f688f7e6 --- /dev/null +++ b/packages/account/test/utils/mockIncompabileVersions.ts @@ -0,0 +1,37 @@ +import * as fuelTsVersionsMod from '@fuel-ts/versions'; +import { versions } from '@fuel-ts/versions'; + +export const mockIncompatibleVersions = (opts: { + isMajorMismatch: boolean; + isMinorMismatch: boolean; +}) => { + const mismatch = (current: string) => (current === '0' ? 1 : parseInt(current, 10) - 1); + + const { isMajorMismatch, isMinorMismatch } = opts; + const { FUEL_CORE } = versions; + const [currentMajor, currentMinor, currentPatch] = FUEL_CORE.split('.'); + const [major, minor, patch] = [ + isMajorMismatch ? mismatch(currentMajor) : currentMajor, + isMinorMismatch ? mismatch(currentMinor) : currentMinor, + currentPatch, + ].map(String); + + const mock = { + isMajorSupported: major !== currentMajor, + isMinorSupported: minor !== currentMinor, + isPatchSupported: patch !== currentPatch, + supportedVersion: `${major}.${minor}.${patch}`, + }; + + if (mock.supportedVersion === FUEL_CORE) { + throw new Error(); + } + + const spy = vi.spyOn(fuelTsVersionsMod, 'checkFuelCoreVersionCompatibility'); + spy.mockImplementationOnce(() => mock); + + return { + current: { FUEL_CORE }, + supported: { FUEL_CORE: mock.supportedVersion }, + }; +}; diff --git a/packages/fuel-gauge/src/abi/abi-script.test.ts b/packages/fuel-gauge/src/abi/abi-script.test.ts index e92ef9b448d..c6eb5eecb05 100644 --- a/packages/fuel-gauge/src/abi/abi-script.test.ts +++ b/packages/fuel-gauge/src/abi/abi-script.test.ts @@ -10,6 +10,10 @@ import { } from '../../test/typegen/scripts/ScriptWithComplexArgs'; import type { Vec } from '../../test/typegen/scripts/common'; +/** + * @group browser + * @group node + */ describe('abi-script', () => { describe('decodeArguments', () => { it('should decode arguments with a simple script', async () => { @@ -53,13 +57,21 @@ describe('abi-script', () => { >; const arg5 = { Address: { bits: getRandomB256() } }; const arg6 = 100; + const expected = [ + expect.toEqualBn(arg1), + arg2, + expect.toEqualBn(arg3), + arg4, + arg5, + expect.toEqualBn(arg6), + ]; // Run script const script = new ScriptWithComplexArgs(wallet); const args: ScriptWithComplexArgsInputs = [arg1, arg2, arg3, arg4, arg5, arg6]; const tx = await script.functions.main(...args).call(); const { value, transactionResult } = await tx.waitForResult(); - expect(value).toEqual(true); + expect(value).toEqual(expected); // Assert script data const scriptData = transactionResult.transaction.scriptData; @@ -70,14 +82,7 @@ describe('abi-script', () => { // Assert the decoded script data matches the input arguments const fn = script.interface.getFunction('main'); const decoded = fn.decodeArguments(scriptData); - expect(decoded).toEqual([ - expect.toEqualBn(arg1), - arg2, - expect.toEqualBn(arg3), - arg4, - arg5, - expect.toEqualBn(arg6), - ]); + expect(decoded).toEqual(expected); }); }); }); diff --git a/packages/fuel-gauge/src/mapped-error-messages.test.ts b/packages/fuel-gauge/src/mapped-error-messages.test.ts index 10590ccf4a8..82c88a49e51 100644 --- a/packages/fuel-gauge/src/mapped-error-messages.test.ts +++ b/packages/fuel-gauge/src/mapped-error-messages.test.ts @@ -10,7 +10,7 @@ import { launchTestContract } from './utils'; * @group browser */ describe('mapped error messages', () => { - test('not enough coins error', async () => { + it('should throw not enough coins error', async () => { using contract = await launchTestContract({ factory: CallTestContractFactory }); const emptyWallet = Wallet.generate({ provider: contract.provider }); @@ -23,7 +23,7 @@ describe('mapped error messages', () => { }); }); - test('max coins reached error', async () => { + it('should throw max coins reached error', async () => { using launched = await launchTestNode({ walletsConfig: { amountPerCoin: 1, diff --git a/packages/fuel-gauge/test/fixtures/forc-projects/script-with-complex-args/src/main.sw b/packages/fuel-gauge/test/fixtures/forc-projects/script-with-complex-args/src/main.sw index 4e6291450d6..5431991fcfc 100644 --- a/packages/fuel-gauge/test/fixtures/forc-projects/script-with-complex-args/src/main.sw +++ b/packages/fuel-gauge/test/fixtures/forc-projects/script-with-complex-args/src/main.sw @@ -2,7 +2,9 @@ script; use std::bytes::Bytes; -pub type PoolId = (AssetId, AssetId, bool); +type PoolId = (AssetId, AssetId, bool); + +type ScriptResult = (u64, AssetId, u64, Vec, Identity, u32); fn main( amount_in: u64, @@ -11,6 +13,6 @@ fn main( pools: Vec, recipient: Identity, deadline: u32, -) -> bool { - return true; +) -> ScriptResult { + return (amount_in, asset_in, amount_out_min, pools, recipient, deadline); }