Transactions

Create transactions for sending assets.

Send ADA to Addresses

You can chain the component to send to multiple recipients. For each recipients, append:

tx.sendLovelace(address: Recipient, lovelace: string);

Where Recipient is a string or an object with the following properties:

Recipient = string | {
  address: string;
  datum?: {
      value: Data;
      inline?: boolean | undefined;
  } | undefined;
  script?: NativeScript | PlutusScript | undefined;
}

.build() constructs the transaction and returns a transaction CBOR. Behind the scenes, it selects all of the necessary inputs belonging to the wallet, calculates the fee for this transaction and returns the remaining assets to the change address. Use wallet.signTx() to sign transaction CBOR.

import { Transaction } from '@meshsdk/core';

const tx = new Transaction({ initiator: wallet })
  .sendLovelace(
    'addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr',
    '1000000'
  )
;

const unsignedTx = await tx.build();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
Send ADA to recipients

Add or remove recipients, input the address and the amount of ADA to send.

Recipients
Recipient #1

Send Multiple Assets to Addresses

Use sendAssets() to send native assets to one or more recipients:

tx.sendAssets(recipient: Recipient, assets: Asset[])

For each recipient, we define a list of Asset to send:

import type { Asset } from '@meshsdk/core';

let assets: Asset[] = [];
for (const asset of nativeAssets) {
  let thisAsset = {
    unit: '64af286e2ad0df4de2e7de15f8ff5b3d27faecf4ab2757056d860a424d657368546f6b656e',
    quantity: '1',
  };
  assets.push(thisAsset);
}
tx.sendAssets(recipient.address, assets);

We can chain a series of tx.sendAssets() and tx.sendLovelace() to send multiple assets to multiple recipients.

import { Transaction } from '@meshsdk/core';
import type { Asset } from '@meshsdk/core';

const tx = new Transaction({ initiator: wallet })
  .sendLovelace(
    'addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr',
    '1000000'
  )
  .sendAssets(
    'addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr',
    [
      {
        unit: '64af286e2ad0df4de2e7de15f8ff5b3d27faecf4ab2757056d860a424d657368546f6b656e',
        quantity: '1',
      },
    ]
  );

const unsignedTx = await tx.build();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
Send multi-assets to recipients

Add or remove recipients, input the address and the amount of ADA to send.

Recipients
Recipient #1
No wallets installed

Send Token to Addresses

We can chain sendToken() commands to send to multiple recipients. For each recipient, append like so:

tx.sendToken(recipient: Recipient, ticker: token, amount: string);

Like sendAssets(), we can chain sendToken() together with tx.sendAssets() to send multiple assets to multiple recipients.

import { Transaction } from '@meshsdk/core';

const tx = new Transaction({ initiator: wallet })
  .sendToken(
    'addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr', 
    'DJED', 
    '1000000'
  )
;

const unsignedTx = await tx.build();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
Send tokens to recipients

Add or remove recipients, input the address and the amount tokens to send.

Recipients
Recipient #1
No wallets installed

Send Assets to Handle

Send assets to a handler.

We can get the ADA Handle's address with fetchHandleAddress():

import { KoiosProvider } from '@meshsdk/core';

const koios = new KoiosProvider('api');
const address = await koios.fetchHandleAddress('jingles');

Next, we can create a transactions, for instance, lets send some lovelace to jingles:

import { KoiosProvider, Transaction } from '@meshsdk/core';

const koios = new KoiosProvider('api');

const tx = new Transaction({ initiator: wallet })
  .sendLovelace(
    await koios.fetchHandleAddress('jingles'),
    '1000000'
);

const unsignedTx = await tx.build();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
Send ADA to handle

Note: this demo only works on mainnet.

Recipients
No wallets installed

Send Value to Addresses

Specify an output for the transaction. This funcion allows you to design the output UTXOs, either by splitting the outputs from multiple UTxOs or by creating reference inputs.

tx.sendValue(address: Recipient, value: UTxO);

import { Transaction } from '@meshsdk/core';

const tx = new Transaction({ initiator: wallet })
  .sendValue(recipient, UTxO);

const unsignedTx = await tx.build();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);

where UTxO has the following format:

{
  input: {
      outputIndex: number;
      txHash: string;
  };
  output: {
      address: string;
      amount: Asset[];
      dataHash?: string;
      plutusData?: string;
      scriptRef?: string;
  };
}

Coin selection

There are currently three coin selection algorithms available:

  • Largest First
  • Largest First Multi-Asset
  • Keep Relevant

Largest First

To select UTXOs for transaction that only requires lovelace, use largestFirst.

largestFirst = (
  lovelace: Quantity, initialUTxOSet: UTxO[], includeTxFees = false,
  { maxTxSize, minFeeA, minFeeB } = DEFAULT_PROTOCOL_PARAMETERS,
): UTxO[]

For example, selecting the UTXOs for sending 10000000 lovelace:

import { largestFirst } from '@meshsdk/core';

const utxos = await wallet.getUtxos();

const costLovelace = '10000000';
const selectedUtxos = largestFirst(costLovelace, utxos, true);

Largest First Multi-Asset

largestFirstMultiAsset allows you to define which native assets you require for sending out by defining a Map. The Map is matches the Unit with the quantity of each asset.

largestFirstMultiAsset = (
  requestedOutputSet: Map<Unit, Quantity>, initialUTxOSet: UTxO[],
  includeTxFees = false, parameters = DEFAULT_PROTOCOL_PARAMETERS,
): UTxO[]

Note that if lovelace, aside from the "minimum Ada" which in any case needs to accompany the other assets, this must be explicitly specified. This can also be useful in the case that your transaction only requires transfer of lovelace. In this case, the algorithm will exclude all multiasset UTxOs from the selection, which can result in more efficient selection of the required UTxOs.

import { largestFirstMultiAsset } from '@meshsdk/core';
import type { Unit, Quantity } from '@meshsdk/core';

const utxos = await wallet.getUtxos();

const assetMap = new Map<Unit, Quantity>();
assetMap.set(
  'd9312da562da182b02322fd8acb536f37eb9d29fba7c49dc172555274d657368546f6b656e',
  '1'
);
// if you need to include lovelace
assetMap.set(
  'lovelace',
  '10000000'
);
// if you need to include more than 1 native asset
assetMap.set(
  'another asset unit',
  '1'
);

const selectedUtxos = largestFirstMultiAsset(assetMap, utxos, true);

The third parameter is includeTxFees. If True, Mesh will calculate the fees required for the transaction, and include additional UTxOs to necessary to fulfill the fees requirements.

Keep Relevant

keepRelevant is a two-step coin selection algorithm. First, given a Map (of requested assets and respective quantities) and a set of UTxOs, it tries to eliminate the irrelevant UTxOs from the set. Next, it checks that this UTxO set includes enough lovelace to cover all/any multi-assets in the set. If the set does not include enough lovelace, then it will try to also pick up another UTxO from the wallet, containing the largest amount of lovelace.

keepRelevant = (
  requestedOutputSet: Map<Unit, Quantity>,
  initialUTxOSet: UTxO[],
  minimumLovelaceRequired = '5000000',
);

Here is an example how you can use keepRelevant():

import { keepRelevant } from '@meshsdk/core';
import type { Unit, Quantity } from '@meshsdk/core';

const utxos = await wallet.getUtxos();

const assetMap = new Map<Unit, Quantity>();
assetMap.set(
  'd9312da562da182b02322fd8acb536f37eb9d29fba7c49dc172555274d657368546f6b656e',
  '1'
);
// if you need to include lovelace
assetMap.set(
  'lovelace',
  '10000000'
);

const selectedUtxos = keepRelevant(assetMap, utxos);

Set Collateral

Specify the UTXOs that you want to use as collateral. This is especially useful if you are using App Wallet.

setCollateral(collateral: UTxO[])

Set Required Signers

Sets the required signers for the transaction. This is useful if you are using App Wallet or in a multi-signature transaction.

setRequiredSigners(addresses: string[])

Set Start and Expire Time

We can define the time-to-live (TTL) for the transaction. TTL is the time limit for our transaction to be included in a blockchain, if it is not in a blockchain by then the transaction will be cancelled. This time limit is defined as slot.

In order to get the slot of the time you wish the transaction would expire, you can use resolveSlotNo. For example, if you would like the transaction to expire in 5 minutes, you can get the slot in the following way:

import { resolveSlotNo } from '@meshsdk/core';
let minutes = 5; // add 5 minutes
let nowDateTime = new Date();
let dateTimeAdd5Min = new Date(nowDateTime.getTime() + minutes*60000);
const slot = resolveSlotNo('mainnet', dateTimeAdd5Min.getTime());

Next, we set the TTL with setTimeToExpire and providing the slot, this means that if the transaction is submitted after after slot will not be valid.

const tx = new Transaction({ initiator: wallet });
// do tx.sendLovelace() or any transactions actions
tx.setTimeToExpire(slot)
const unsignedTx = await tx.build();

Likewise, we can set a "validity start interval" for the transaction, where it is the time the transaction will be valid. We can define the start time with setTimeToStart and providing the slot:

const tx = new Transaction({ initiator: wallet });
// do tx.sendLovelace() or any transactions actions
tx.setTimeToStart(slot)
const unsignedTx = await tx.build();

Note that, if you are using a policy locking script, you must define setTimeToExpire before the expiry; otherwise, you will catch the ScriptWitnessNotValidatingUTXOW error.

Set Metadata

Cardano Transaction Metadata specifies that any transaction can include arbitrary metadata which is then stored immutably in the blockchain. Metadata take the form of text, specific structured text, numbers, hashes, any combination of these, etc. If the content of metadata should remain secret, then it is the responsibility of the sender to first encrypt it. There are many use cases: for example, when combined with off-chain infrastructure (eg physical identifiers), metadata can act as a confirmation or assurance of authenticity. The current protocol parameters define the maximum size of metadata permitted to accompany each transaction.

Some uses for metadata:

  • Validation and verification. Checking and verifying external physical objects and legitimate content, for example by coupling with a physical identifier such as a QR-code. This can be especially beneficial for low-cost supply chain tracking of fast-moving consumer goods.
  • Authentication and attribution. Confirming the authenticity of credentials received from an educational institution or membership group, using the fact that metadata can serve as an immutable and always-accessible evidence of certification.
  • Secure record of information. Saving vital information, so nobody one can alter it afterwards, meaning it will last as long as the Cardano blockchain exists.

You can insert metadata into a transaction with setMetadata(key, value). The key is a number, and value is a string.

import { Transaction } from '@meshsdk/core';

const tx = new Transaction({ initiator: wallet });
tx.sendLovelace(
  'addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr',
  '1000000'
);
tx.setMetadata(0, 'Transaction message');
No wallets installed