Icon HelpCircleForumIcon Link

⌘K

Icon HelpCircleForumIcon Link

Icon LinkTypeScript SDK Migrations Guide

Icon LinkNovember 15, 2024

Release v0.97.0 Icon Link

Icon LinkonDeploy fuels config supports all Sway program types - #3383 Icon Link

  • Changed the outputted data from the onDeploy callback method for the fuels.config.ts. Instead of just emitting the deployed contracts (as an array), it will now emit an object with contracts, predicates and scripts.
// Before (fuels.config.ts)
import { createConfig, FuelsConfig, DeployedContract } from 'fuels';
 
export default createConfig({
  output: 'dir/out',
  onDeploy: (config: FuelsConfig, deployedContracts: DeployedContract[]) => {
    console.log('contracts', deployedContracts);
  }
});
// After (fuels.config.ts)
import { createConfig, FuelsConfig, DeployedData } from 'fuels';
 
export default createConfig({
  output: 'dir/out',
  onDeploy: (config: FuelsConfig, deployed: DeployedData[]) => {
    console.log('contracts', deployed.contracts);
    console.log('predicates', deployed.predicates);
    console.log('scripts', deployed.scripts);
  }
});

Icon LinkRemove unnecessary nonce from message gql queries - #3298 Icon Link

  • Removed the nonce property from Provider.operations.getMessageByNonce(). This can still be retrieved by Provider.getMessageByNonce().

Icon LinkRefactor predicate and script deployment - #3389 Icon Link

ContractFactory.deployAsBlobTxForScript has been removed in favor of Predicate.deploy and Script.deploy:

// before
const factory = new ContractFactory(scriptBytecode, scriptAbi, wallet);
const { waitForResult } = await factory.deployAsBlobTxForScript();
const { loaderBytecode, configurableOffsetDiff } = await waitForResult();
 
// after
const script = new Script(scriptBytecode, scriptAbi, wallet);
const { blobId, waitForResult } = await script.deploy(deployerWallet);
const loaderScript = await waitForResult();
 
const predicate = new Predicate({ bytecode, abi, provider });
const { blobId, waitForResult } = await predicate.deploy(deployerWallet);
const loaderPredicate = await waitForResult();

Icon LinkMandate abi in Predicate constructor - #3387 Icon Link

  • Instantiating a Predicate now requires providing its abi. If you want to use the Predicate as an Account, please instantiate it via the Account class
// before
const predicate = new Predicate({ provider, bytecode }); // worked even though abi is missing
 
// after
const predicate = new Predicate({ abi, provider, bytecode }); // abi is now mandatory
 
// predicate as account
const account = new Account(predicateAddress, provider);

Icon LinkOptimize getTransactions query - #3336 Icon Link

  • The response format for Provider.getTransactions remains the same. However, the response format for the query Provider.operations.getTransactions has been modified.
// before
query getTransactions {
  id
  rawPayload
  status {
    ...
  }
}
// after
query getTransactions {
  rawPayload
}

Icon LinkLimit TX pagination number for getTransactionsSummaries - #3400 Icon Link

  • The pagination number for getTransactionsSummaries is limited to 60 now
// before
const { transactions } = await getTransactionsSummaries({
  provider,
  filters: {
    owner: account.address.toB256(),
    first: 200,
  },
});
// after
const { transactions } = await getTransactionsSummaries({
  provider,
  filters: {
    owner: account.address.toB256(),
    first: 60, // Limit is 60 now. A higher value will result in an error
  },
});

Icon LinkRemove blockId in transaction list responses - #3379 Icon Link

  • The blockId property has been removed from the following GraphQL queries used to list past transactions:
const { transactions } = await getTransactionsSummaries({ ... });
 
const { transactionsByOwner } = await provider.operations.getTransactionsByOwner({ ... });

If the blockId is required for a given transaction, it needs to be queried separately with getTransactionSummary helper:

import { getTransactionSummary } from 'fuels';
 
const transaction = await getTransactionSummary({
  id,
  provider,
});

Note: The blockId is still available in the result for a submitted transaction.

Icon LinkOptimize coin gql queries - #3301 Icon Link

  • The Provider.operations.getCoins() and Provider.operations.getCoinsToSpend function no longer return the owner. These methods shouldn't be called directly but are used internally to formulate responses from the SDK.

  • Removed the property owner from the Provider.operations.getCoinsToSpend() function. Suggest to use the owner from the input parameters.

Icon LinkOctober 13, 2024

Release v0.96.0 Icon Link

Icon LinkChecksum method to remove 0x before hashing - #3313 Icon Link

We fixed the checksum utilities:

  • Address.toChecksum()
  • Address.isChecksumValid()

Now, we correctly remove the leading 0x before hashing the address.

Because of this, previous values were invalid, and the update is required.

Icon LinkOctober 10, 2024

Release v0.95.0 Icon Link

Icon LinkBump transaction pagination limit to 60 - #3306 Icon Link

  • A limit was added of 60 transactions to the provider.getTransactions() method.

Icon LinkMade Address toString and valueOf returns checksum - #3310 Icon Link

The return of both Address.toString() and Address.valueOf was modified to return the address checksum instead of the Bech32 string

// before
const address = new Address('fuel1elnmzsav56dqnp95sx4e2pckq36cvae9ser44m5zlvgtwxw49fmqd7e42e');
 
address.toString()
// fuel1elnmzsav56dqnp95sx4e2pckq36cvae9ser44m5zlvgtwxw49fmqd7e42e
 
address.valueOf()
// fuel1elnmzsav56dqnp95sx4e2pckq36cvae9ser44m5zlvgtwxw49fmqd7e42e
// after
const address = new Address('fuel1elnmzsav56dqnp95sx4e2pckq36cvae9ser44m5zlvgtwxw49fmqd7e42e');
 
address.toString()
// 0xEf86aFa9696Cf0dc6385e2C407A6e159A1103cEfB7E2Ae0636FB33d3cb2A9E4A
 
address.valueOf()
// 0xEf86aFa9696Cf0dc6385e2C407A6e159A1103cEfB7E2Ae0636FB33d3cb2A9E4A

Icon LinkSlim down chainInfoFragment and GasCostsFragment - #3286 Icon Link

  • latestBlock is no longer part of the ChainInfo return of provider.getChain(). You can fetch it via provider.getBlock('latest').
  • ChainInfo['consensusParameters']['gasCosts'] has been slimmed down to only contain data necessary for the operation of the SDK. Up until now, the SDK was fetching more than it needed. If this change affects you, you will have to create a custom graphql query for gasCosts for the additional data you need.

Icon LinkOptimize balance queries - #3296 Icon Link

  • Removed the owner and assetId properties from the response of Provider.operations.getBalance(). These properties are also required arguments to execute the function so are redundant in the response. Should you require these values, you should take them from the values that you passed to the function.
  • Removed the owner property from the response of Provider.operations.getBalances(). This property is a required argument to execute the function so is redundant in the response. Should you require this value, you should take it from the value that you passed to the function.

Icon LinkAugust 30, 2024

Release v0.94.0 Icon Link

Icon LinkConsider message on resources cache - #2872 Icon Link

The provider option flag cacheUtxo was renamed to resourceCacheTTL

// before
const provider = await Provider.create(FUEL_NETWORK_URL, {
  cacheUtxo: 5000,
});
 
 
using launched = await launchTestNode({
  providerOptions: {
    cacheUtxo: 5000,
  },
});
// after
const provider = await Provider.create(FUEL_NETWORK_URL, {
  resourceCacheTTL: 5000,
});
 
using launched = await launchTestNode({
  providerOptions: {
    resourceCacheTTL: 5000,
  },
});

Icon LinkPrettify typegen api - #2824 Icon Link

Icon LinkPredicate class

  • Predicate class constructor parameters renamed: inputData > data
// before
import { Predicate } from 'fuels';
 
const predicate = new Predicate({
  ...unchangedParameters,
  inputData,
});
// after
import { Predicate } from 'fuels';
 
const predicate = new Predicate({
  ...unchangedParameters,
  data,
});
  • Typegen extended/generated Predicate now accepts a single parameter for initialization
// before
import { TestPredicateAbi__factory } from './typegend';
 
TestPredicateAbi__factory.createInstance(provider, data, configurableConstants);
// after
import { TestPredicate } from './typegen';
 
new TestPredicate({
  provider,
  data,
  configurableConstants
});

Icon LinklaunchTestNode utility

  • Renamed contractsConfigs[].deployer to contractsConfigs[].factory
  • Removed contractsConfigs[].bytecode and .hex.ts file

The bytecode is now saved within the factory class, so you don't have to deal with it.

// before
import { TokenAbi__factory } from './typegend';
import TokenAbiHex from './typegend/contracts/TokenAbi.hex';
 
using launched = await launchTestNode({
  contractsConfigs: [{
    deployer: TokenAbi__factory,
    bytecode: TokenAbiHex
  }],
});
// after
import { TokenFactory } from './typegend';
 
using launched = await launchTestNode({
  contractsConfigs: [{
    factory: TokenFactory,
  }],
})

Icon LinkRenamed method deployContract to deploy

Removed the redundant suffix on the ContractFactory class method name.

// before
import { ContractFactory } from 'fuels';
 
const factory = new ContractFactory(wallet);
 
factory.deployContract();
// after
import { ContractFactory } from 'fuels';
 
const factory = new ContractFactory(wallet);
 
factory.deploy();

Icon LinkTypegen Contract template

  • Removed Abi__factory suffix from class names
  • The file <name>.hex was removed (access it via <Name>.bytecode)
  • The files <name>__factory.ts and <name>.d.dts were merged into <name>.ts
  • The class <Name> and the interface <Name>Abi are now just <Name>
  • Method <Name>Factory.deployContract() renamed to <Name>Factory.deploy()
  • You may need to remove the previously generated <typegenDir>/contracts/factories directory
// before
import { TestContractAbi, TestContract__factory } from './typegen'
import testContractBytecode from './typegen/contracts/TestContract.hex'
 
const instance = await TestContract__factory.connect(id, wallet);
 
const deploy = await TestContract__factory.deployContract(testContractBytecode, wallet);
const { contract } = await deploy.waitForResult();
// after
import { TestContract, TestContractFactory } from './typegen'
 
const instance = new TestContract(id, wallet);
 
const deploy = await TestContractFactory.deploy(wallet);
const { contract } = await deploy.waitForResult();

Icon LinkTypegen Predicate template

  • Removed Abi__factory suffix from class names
  • Started accepting a single parameter object in constructor
  • You may need to remove the previously generated <typegenDir>/predicates/factories directory
// before
import { TestPredicateAbi__factory } from './typegen'
 
const predicate = TestPredicateAbi__factory.createInstance(provider);
// after
import { TestPredicate } from './typegen'
 
const predicate = new TestPredicate({ provider });

Icon LinkTypegen Script template

  • Removed Abi__factory suffix from class names
  • You may need to remove the previously generated <typegenDir>/scripts/factories directory
// before
import { TestPredicateAbi__factory } from './typegen'
 
const script = TestScriptAbi__factory.createInstance(wallet);
// after
import { TestPredicate } from './typegen'
 
const script = new TestScript(wallet);

Icon LinkNon-blocking blob deployment - #2929 Icon Link

The transaction ID from a contract deployment is now returned as a promise.

// before
import { ContractFactory } from 'fuels';
 
const factory = new ContractFactory(bytecode, abi, wallet);
const { waitForResult, contractId, transactionId } = await factory.deploy();
console.log(transactionId); // 0x123....
// after
import { ContractFactory } from 'fuels';
 
const factory = new ContractFactory(bytecode, abi, wallet);
const { waitForResult, contractId, waitForTransactionId } = await factory.deploy();
const transactionId = await waitForTransactionId();
console.log(transactionId); // 0x123....

Icon LinkImprove () and Option<T> type handling - #2777 Icon Link

  • () and Option<T> Sway types are now either required or optional, dependent on where the argument appears in the function arguments.

Given these Sway functions:

fn type_then_void_then_type(x: u8, y: (), z: u8) -> ()
fn type_then_void_then_void(x: u8, y: (), z: ()) -> ()
 
fn type_then_option_then_type(x: u8, y: Option<u8>, z: u8) -> ()
fn type_then_option_then_option(x: u8, y: Option<u8>, z: Option<u8>) -> ()

This is what changes:

// before
contract.functions.type_then_void_then_type(42, 43)
contract.functions.type_then_void_then_void(42) // Unchanged
 
contract.functions.type_then_option_then_type(42, undefined, 43)
contract.functions.type_then_option_then_option(42, undefined, undefined)
// after
contract.functions.type_then_void_then_type(42, undefined, 43)
contract.functions.type_then_void_then_void(42) // Unchanged
 
contract.functions.type_then_option_then_type(42, undefined, 43)
contract.functions.type_then_option_then_option(42)

Icon Linkfuel-core@0.32.1 and large contract deployments - #2827 Icon Link

MAX_CONTRACT_SIZE is no longer exported, it should now be fetched from the chain.

// before
import { MAX_CONTRACT_SIZE } from 'fuels';
// after
import { Provider, FUEL_NETWORK_URL } from 'fuels';
 
const provider = await Provider.create(FUEL_NETWORK_URL);
const { consensusParameters } = provider.getChain();
const maxContractSize = consensusParameters.contractParameters.contractMaxSize.toNumber();

Icon LinkDeprecate FUEL_NETWORK_URL and LOCAL_NETWORK_URL- #2915 Icon Link

Removed FUEL_NETWORK_URL constant.

// before
import { FUEL_NETWORK_URL } from 'fuels';
 
const provider = await Provider.create(FUEL_NETWORK_URL);
// after
const provider = await Provider.create('https://127.0.0.1:4000/v1/graphql');

Removed LOCAL_NETWORK_URL constant.

// before
import { LOCAL_NETWORK_URL } from 'fuels';
 
const provider = await Provider.create(LOCAL_NETWORK_URL);
// after
const provider = await Provider.create('https://127.0.0.1:4000/v1/graphql');

Icon LinkIntegrate launchTestNode in remaining packages - #2811 Icon Link

Removed generateTestWallet and seedTestWallet utilities.

// before
import { bn } from "@fuel-ts/math";
import {
  seedTestWallet,
  generateTestWallet,
} from "@fuel-ts/account/test-utils";
 
const provider = await Provider.create("http://127.0.0.1:4000/v1/graphql");
 
// seeding
const walletA = Wallet.fromPrivateKey("0x...", provider);
const baseAssetId = provider.getBaseAssetId();
seedTestWallet(wallet, [{ assetId: baseAssetId, amount: bn(100_000) }]);
 
// generating
const walletB = await generateTestWallet(provider, [[1_000, baseAssetId]]);
// after
import { launchTestNode } from 'fuels/test-utils';
 
// create two wallets seeded with 100_000 units of the base asset
using launched = await launchTestNode({
  walletsConfig: {
    count: 2,
    amountPerCoin: 100_000,
  },
});
 
const {
  wallets: [walletA, walletB]
} = launched;
 
const balance = await walletA.getBalance() // 100_000

Removed launchNodeAndGetWallets utility.

// before
import { launchNodeAndGetWallets } from 'fuels/test-utils';
 
const { provider, wallets } = await launchNodeAndGetWallets();
// after
import { launchTestNode } from 'fuels/test-utils';
 
using launched = await launchTestNode();
 
const { provider, wallets } = launched;

Icon LinkRenamed AssetId to TestAssetId- #2905 Icon Link

Renamed testing class AssetId to TestAssetId.

// before
import { AssetId } from 'fuels/test-utils';
 
const [assetA] = AssetId.random();
// after
import { TestAssetId } from 'fuels/test-utils';
 
const [assetA] = TestAssetId.random();

Icon LinkAdding abi transpiler - #2856 Icon Link

New ABI spec

The SDK now adheres to the new specs introduced via:

Check these out to understand all its changes.

The class AbiCoder is no longer exported, and the way to do encoding and decoding of specific types is now via the Interface.encodeType and Interface.decodeType methods:

// before
const abi = yourAbi;
const functionArg = abi.functions.inputs[0];
 
const encoded = AbiCoder.encode(abi, functionArg, valueToEncode);
const decoded = AbiCoder.decode(abi, functionArg, valueToDecode, 0);
// after
import { Interface } from 'fuels';
 
const abi = yourAbi;
const functionArg = abi.functions.inputs[0];
 
const abiInterface = new Interface(abi);
 
const encoded = abiInterface.encodeType(functionArg.concreteTypeId, valueToEncode);
const decoded = abiInterface.decodeType(functionArg.concreteTypeId, valueToDecode);

Previously, you could get a type from the ABI via the Interface.findTypeById. This method has been removed after introducing the new abi specification because the concept of a type has been split into concrete types and metadata types. If you want a specific type, you can get it directly from the ABI.

// before
const abiInterface = new Interface(abi);
 
// internally this method searched the abi types:
// abi.types.find(t => t.typeId === id);
const type = abiInterface.findTypeById(id);
// after
import { Interface } from 'fuels';
 
// search the types on the abi directly
const concreteType = abi.concreteTypes.find(ct => ct.concreteTypeId === id);
const metadataType = abiInterface.jsonAbi.metadataTypes.find(mt => mt.metadataTypeId === id);

The JsonAbiArgument type isn't part of the new ABI spec (#596 Icon Link, #599 Icon Link) as such so we stopped exporting it. Its closest equivalent now would be a concrete type because it fully defines a type.

// before
const arg: JsonAbiArgument = {...};
// after
import { Interface } from 'fuels';
 
type ConcreteType = JsonAbi["concreteTypes"][number]
const arg: ConcreteType = {...};

Icon LinkRead malleable fields from transaction status on subscription - #2962 Icon Link

Removed TransactionResult.gqlTransaction. You can use the TransactionResult.transaction field instead, which has all the data that TransactionResult.gqlTransaction has but already decoded.

// before
const { gqlTransaction } = await new TransactionResponse('your-tx-id').waitForResult();
// after
const { transaction } = await new TransactionResponse('your-tx-id').waitForResult();

Icon LinkFix assembly process for account transfer operation - #2963 Icon Link

The getTransferOperations helper function now requires an additional baseAssetId parameter.

// before
const transferOperations = getTransferOperations({ inputs, outputs, receipts })
// after
const transferOperations = getTransferOperations({ inputs, outputs, receipts, baseAssetId })

Icon LinkWrap subscriptions in promise - #2964 Icon Link

// before
const subscription = provider.operations.statusChange({ transactionId });
for await (const response of subscription) { ... }
// after
const subscription = await provider.operations.statusChange({ transactionId });
for await (const response of subscription) { ... }

Icon LinkJuly 30, 2024

Release v0.93.0 Icon Link

Icon LinkDeploy contract validation - #2796 Icon Link

ErrorCode.INVALID_TRANSACTION_TYPE was migrated to ErrorCode.UNSUPPORTED_TRANSACTION_TYPE.

// before
const code = ErrorCode.INVALID_TRANSACTION_TYPE;
// after
const code = ErrorCode.UNSUPPORTED_TRANSACTION_TYPE;

Icon LinkRemove awaitExecution functionality - #2820 Icon Link

It is no longer possible to submit transactions using the awaitExecution flag and wait for the transaction to be processed at submission:

// before
const response = await account.sendTransaction(transactionRequest, { awaitExecution: true });
// after
const submit = await account.sendTransaction(transactionRequest);
 
const response = await submit.waitForResult();

Icon LinkRefactored the getTransactionCost method - #2643 Icon Link

Refactored functionality for Provider.getTransactionCost to Account.getTransactionCost and changed estimation parameter from quantitiesToContract to quantities.

// before
const provider = Provider.create(...);
const account = Wallet.generate({ ... }) || new Predicate(...);
const quantities: Array<CoinQuantityLike> = [
  { amount: 1000, assetId: provider.getBaseAssetId() }
];
 
const cost = provider.getTransactionCost(txRequest, {
  resourceOwner: account,
  quantitiesToContract: quantities,
})
// after
const provider = Provider.create(...);
const account = Wallet.generate({ ... }) || new Predicate(...);
const quantities: Array<CoinQuantityLike> = [
  { amount: 1000, assetId: provider.getBaseAssetId() }
];
 
const cost = account.getTransactionCost(txRequest, { quantities });

Icon LinkJuly 11, 2024

Release v0.92.0 Icon Link

Icon LinkImplement non-blocking contract call - #2692 Icon Link

The call method in the BaseInvocationScope class no longer waits for transaction execution, making it non-blocking. This change affects how transaction responses are handled.

// before
const { logs, value, transactionResult } = await contract.functions.xyz().call()
// after
const { transactionId, waitForResult } = await contract.functions.xyz().call();
 
const { logs, value, transactionResult } = await waitForResult();

Icon LinkMade deployContract a non-blocking call - #2597 Icon Link

The deployContract method no longer returns the contract instance directly. Instead, it returns an object containing the transactionId , the contractId, and a waitForResult function.

// before
const factory = new ContractFactory(contractByteCode, contractAbi, wallet);
 
const contract = await factory.deployContract();
 
const { value } = await contract.functions.xyz().call();
 
// after
const factory = new ContractFactory(contractByteCode, contractAbi, wallet);
 
const { waitForResult, transactionId, contractId } = await factory.deployContract();
 
const { contract, transactionResult } = await waitForResult();
 
const { value } = await contract.functions.xyz().call();

Icon LinkImplement pagination for Account methods - #2408 Icon Link

// before
const coins = await myWallet.getCoins(baseAssetId);
const messages = await myWallet.getMessages();
const balances = await myWallet.getBalances();
const blocks = await provider.getBlocks();
 
// after
const { coins, pageInfo } = await myWallet.getCoins(baseAssetId);
const { messages, pageInfo } = await myWallet.getMessages();
const { balances } = await myWallet.getBalances();
const { blocks, pageInfo } = await provider.getBlocks();
 
/*
  The `pageInfo` object contains cursor pagination information one
  can use to fetch subsequent pages selectively and on demand.
*/

Icon LinklaunchNode.cleanup not killing node in last test of test group - #2718 Icon Link

The killNode and KillNodeParams functionality has been internalized and the method and interface have been deleted so they're no longer exported. It's marked as a breaking change for pedantic reasons and there shouldn't really be any affected users given that they kill nodes via cleanup which is unchanged, so no migration notes are necessary.

Icon LinkRemove InvocationResult from program package - #2652 Icon Link

The classes FunctionInvocationResult, InvocationCallResult, and InvocationResult have been removed. This change will not affect most users as the response for a contract call or script call remains the same; only the type name has changed.

// before
const callResult: FunctionInvocationResult = await contract.functions.xyz().call()
 
const dryRunResult: InvocationCallResult = await contract.functions.xyz().get()
const dryRunResult: InvocationCallResult = await contract.functions.xyz().dryRun()
const dryRunResult: InvocationCallResult = await contract.functions.xyz().simulate()
 
 
// after
const callResult: FunctionResult = await contract.functions.xyz().call()
 
const dryRunResult: DryRunResult = await contract.functions.xyz().get()
const dryRunResult: DryRunResult = await contract.functions.xyz().dryRun()
const dryRunResult: DryRunResult = await contract.functions.xyz().simulate()