# Transaction Request

A transaction request provides the foundations for submitting a transaction and interacting with the blockchain.

Within Fuel, we have the following transaction types:

- Script
- Create
- Mint

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.

## Creating a Transaction Request

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](../contracts/deploying-contracts.md#2-contract-deployment).

## Modifying a Transaction Request

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.

### Adding `OutputCoin`

Including `OutputCoin`s in the transaction request specifies the UTXOs that will be created once the transaction is processed. These UTXOs represent the amounts being transferred to specified account addresses during the transaction:

```
const provider = new Provider(LOCAL_NETWORK_URL);

const recipient1 = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider);
const recipient2 = Wallet.fromPrivateKey(WALLET_PVT_KEY_2, provider);

const baseAssetId = await provider.getBaseAssetId();
const assetA = TestAssetId.A.value;

const transactionRequest = new ScriptTransactionRequest({
  script: ScriptSum.bytecode,
});

transactionRequest.addCoinOutput(recipient1.address, 1000, baseAssetId);
transactionRequest.addCoinOutput(recipient2.address, 500, assetA);
```

### Estimating and Funding the Transaction Request

Before submitting a transaction, ensure it is fully funded to meet its requirements and cover the associated fees. The `assembleTx` method handles this by returning a fully funded and estimated transaction, ready for submission.

```
const transferAmount = 1000;

const request = new ScriptTransactionRequest({
  script: ScriptSum.bytecode,
});

const baseAssetId = await provider.getBaseAssetId();

request.addCoinOutput(wallet.address, transferAmount, baseAssetId);

const { assembledRequest } = await provider.assembleTx({
  request,
  feePayerAccount: wallet,
  accountCoinQuantities: [
    {
      amount: transferAmount,
      assetId: baseAssetId,
      account: wallet,
      changeOutputAccount: wallet,
    },
  ],
});

await wallet.sendTransaction(assembledRequest);
```

### Manually Fetching Resources

In certain scenarios, you may need to manually fetch resources. This can be achieved using the `getResourcesToSpend` method, which accepts an array of `CoinQuantities` and returns the necessary resources to meet the specified amounts:

```
// Instantiate the transaction request
const transactionRequest = new ScriptTransactionRequest({
  script: ScriptSum.bytecode,
});

const baseAssetId = await provider.getBaseAssetId();
const assetA = TestAssetId.A.value;

// Define the quantities to fetch
const quantities: CoinQuantity[] = [
  {
    amount: bn(10000),
    assetId: baseAssetId,
  },
  {
    amount: bn(100),
    assetId: assetA,
  },
];

// Fetching resources
const resources = await wallet.getResourcesToSpend(quantities);

// Adding resources (coins or messages)
transactionRequest.addResources(resources);
```

#### Manually Fetching Coins or Messages

If needed, you can manually include specific coins or messages in the transaction. However, this approach is generally discouraged and should only be used in scenarios where explicitly adding particular coins or messages to the transaction request is required:

```
// Fetching coins
const { coins } = await wallet.getCoins(baseAssetId);
const { messages } = await wallet.getMessages();

// Adding a specific coin or message
transactionRequest.addCoinInput(coins[0]);
transactionRequest.addMessageInput(messages[0]);
```

### Adding a Contract Input and Output to a Transaction Request

Imagine that you have a Sway script that manually calls a contract:

```
use counter::CounterAbi;
fn main(contract_id: ContractId) -> u64 {
    let counter_contract = abi(CounterAbi, contract_id.into());
    counter_contract.get_count()
}
```

In those cases, you will need to add both an `InputContract` and `OutputContract` to the transaction request:

```
const deploy = await CounterFactory.deploy(wallet);
const { contract } = await deploy.waitForResult();

const transactionRequest = new ScriptTransactionRequest({
  script: ScriptSum.bytecode,
  scriptData: contract.id.toB256(),
});

// Add the contract input and output using the contract ID
transactionRequest.addContractInputAndOutput(contract.id);
```

### Adding a Predicate to a Transaction Request

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: await 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](../predicates/index.md).

### Adding a Witness and Signing a Transaction Request

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:

```
const provider = new Provider(LOCAL_NETWORK_URL);
const accountA = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider);
const accountB = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider);

const transactionRequest = new ScriptTransactionRequest({
  script: ScriptSum.bytecode,
});

// Add a witness directly
// Add a witness signature directly
const signature = await accountA.signTransaction(transactionRequest);
transactionRequest.addWitness(signature);

// Or add multiple via `addAccountWitnesses`
await transactionRequest.addAccountWitnesses([accountB]);
```

A more complex example would when signatures are validated inside the script itself, like this guide [here](../cookbook/sway-script-with-signature-validation.md), .

> **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.

### Getting the Transaction ID for a Transaction Request

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 = await 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.

### Burning assets

Assets can be burnt as part of a transaction that has inputs without associated output change. The SDK validates against this behavior, so we need to explicitly enable this by sending the transaction with the `enableAssetBurn` option set to `true`.

```
const baseAssetId = await provider.getBaseAssetId();
const request = new ScriptTransactionRequest();

const {
  coins: [coin],
} = await sender.getCoins(ASSET_A);

// Add the coin as an input, without a change output
request.addResource(coin);

/**
 * Remove the OutputChange for the specific assetId as it is always added by default
 * when using 'addResource'
 */
request.outputs = request.outputs.filter(
  (output) =>
    output.type !== OutputType.Change || String(output.assetId) !== ASSET_A
);

// Fund the transaction
const { assembledRequest } = await provider.assembleTx({
  request,
  feePayerAccount: sender,
  accountCoinQuantities: [
    {
      amount: '0',
      assetId: baseAssetId,
      account: sender,
      changeOutputAccount: sender,
    },
  ],
});

// Send the transaction with asset burn enabled
const tx = await sender.sendTransaction(assembledRequest, {
  enableAssetBurn: true,
});
```

> **Note**: Burning assets is permanent and all assets burnt will be lost. Therefore, be mindful of the usage of this functionality.
