A transaction request provides the foundations for submitting a transaction and interacting with the blockchain.
Within Fuel, we have the following transaction types:
The SDK provides class helpers for handling script and create transactions: ScriptTransactionRequest
and CreateTransactionRequest
, respectively.
Note: Mint transactions can only be created by the block producer and do not have any use outside of block creation. Therefore, the SDK only provides the ability to decode them.
To create a transaction request, you must first instantiate either a ScriptTransactionRequest
or CreateTransactionRequest
.
A ScriptTransactionRequest
is used for script transactions, which allows you to execute bytecode on chain to perform a task or chain of tasks. Within the SDK they can be created like so:
import {
CreateTransactionRequest,
ScriptTransactionRequest,
ZeroBytes32,
} from 'fuels';
import { ScriptSum } from '../../typegend';
// Instantiate the transaction request using a ScriptTransactionRequest
const scriptTransactionRequest = new ScriptTransactionRequest({
script: ScriptSum.bytecode,
});
const scriptData = [1];
// Set the script main function arguments (can also be passed in the class constructor)
scriptTransactionRequest.setData(ScriptSum.abi, scriptData);
A CreateTransactionRequest
is used for create transactions, which are transactions that create a new contract on the blockchain.
// Instantiate the transaction request using a CreateTransactionRequest
const createTransactionRequest = new CreateTransactionRequest({
witnesses: [contractByteCode],
});
Note: We recommend you use the
ContractFactory
for contract deployment as this will shape the create transaction request for you. Information on this can be found in the contract deployment guide .
Once you have instantiated a transaction request, you can modify it by setting the transaction parameters and policies. This can either be done manually by directly altering the transaction request object, or through helper methods that are available on the above classes.
Resources populate the inputs and outputs of a transaction request. This can take the form of coins, messages or contracts. The SDK provides a range of methods for dealing with resources. Below will detail how coins and messages can be added to a transaction request.
// Instantiate the transaction request
const transactionRequest = new ScriptTransactionRequest({
script: ScriptSum.bytecode,
});
// Adding resources (coins or messages)
transactionRequest.addResources(resources);
transactionRequest.addResource(resource);
// Adding coin inputs and outputs (including transfer to recipient)
transactionRequest.addCoinInput(coin);
transactionRequest.addCoinOutput(
recipientAddress,
1000,
provider.getBaseAssetId()
);
// Adding message inputs
transactionRequest.addMessageInput(message);
Scripts can perform multiple actions on chain, therefore you may want to chain contract calls. For this you will need to add a contract to the transaction request. This can be done like so:
const deploy = await CounterFactory.deploy(wallet);
const { contract } = await deploy.waitForResult();
// Add the contract input and output using the contract ID
transactionRequest.addContractInputAndOutput(contract.id);
Predicates are used to define the conditions under which a transaction can be executed. Therefore you may want to add a predicate to a transaction request to unlock funds that are utilized by a script. This can be added like so:
// Instantiate the transaction request
const transactionRequest = new ScriptTransactionRequest({
script: ScriptSum.bytecode,
});
const predicateArguments = [ZeroBytes32];
/**
* Instantiate the predicate and pass valid input data to validate
* the predicate and unlock the funds
*/
const predicate = new Predicate({
bytecode: SimplePredicate.bytecode,
abi: SimplePredicate.abi,
data: predicateArguments,
provider,
});
// Fund the predicate
const tx = await wallet.transfer(predicate.address, bn(100_000));
await tx.waitForResult();
const predicateCoins = await predicate.getResourcesToSpend([
{ amount: 2000, assetId: provider.getBaseAssetId() },
]);
// Add the predicate input and resources
transactionRequest.addResources(predicateCoins);
Note: For more information on predicates, including information on configuring them, funding them and using them to unlock funds, please refer to the predicate guide .
The SDK provides a way of either modifying the witnesses for a transaction request directly, or by passing accounts. This will then sign the transaction request with the account's private key. Below will detail how to add a witness to a transaction request:
// Add a witness directly
transactionRequest.addWitness(witness);
// Add a witness using an account
const account: Account = WalletUnlocked.generate({ provider });
await transactionRequest.addAccountWitnesses(account);
A more complex example of adding multiple witnesses to a transaction request can be seen in the multiple signers guide here , which validates the signatures inside the script itself.
Note: Once
addAccountWitnesses
has been called, any additional modifications to the transaction request will invalidate the signature as the transaction ID changes. Therefore, it is recommended to add witnesses last.
The transaction ID is a SHA-256 hash of the entire transaction request. This can be useful for tracking the transaction on chain. To get the transaction ID, you can use the following method:
// Get the chain ID
const chainId = provider.getChainId();
// Get the transaction ID using the Chain ID
const transactionId = transactionRequest.getTransactionId(chainId);
// TX ID: 0x420f6...
Note: Any changes made to a transaction request will alter the transaction ID. Therefore, you should only get the transaction ID after all modifications have been made.