Batching transactions

Batch/BatchAll functions

The batchTxHex and batchAllTxHex functions can be implemented into the transaction execution process. Both functions operate similarly and require the same inputs. The key distinction lies in the execution sequence: the "batch" variant proceeds with transactions until encountering a failure, ceasing any further actions from the batch. The first successful transactions from the batch will be kept in the blockchain state. In contrast, "batchAll" attempts all transactions. If any transaction fails, it will revert to the preceding successful block without registering any information, thereby leaving the blockchain's state unaltered. The recommended approach is typically to opt for the batchAll transaction. This is the safest way to register all the transactions from the batch, otherwise, you will need to manually handle performed and failed transactions.

Quick summary:

  • In case of failure within a batch transaction, the process stops where it is, and the chain records the first validated transactions.

  • In case of failure within a batchAll transaction, the chain reverts each validated extrinsics from the batch and the blockchain's state remains unaltered.

To get a deep understanding of how batching works on the Ternoa chain, read this article.

Similarly, batchTx and batchAllTx functions are available, providing transaction hashes, not in hexadecimal format. These functions mirror each other in functionality.

For instance, in scenarios involving the creation of many NFTs, it's advantageous to group multiple operations into a single transaction rather than processing each NFT individually. This method is not only cost-effective in terms of transaction fees, but it also significantly reduces the time spent on these operations.

Example: Batching a mint of NFT

We'd typically use the batchAllTxHex function, especially when we want the process to halt and revert in the event of an error, while also receiving the result in hexadecimal format. However, it's important to note that the same code can be applied with batchTxHex, batchTx, or batchAllTx, as all these functions are compatible with the process.


export const nftsBatchMintingHex = async (nftMetadata, quantity) => {
  // nftMetaData represents here the off-chain datas of the NFT.
  // quantity is the number of NFT to be minted
  try{
  ...
    // First we create the NFT
    const nftTx = await createNftTx(nftMetadata, 0, undefined, false)
    // Second we add all the NFT in an Array
    const nftsTxs = new Array(Number(quantity)).fill(nftTx)
    // We batch the transaction with the batchAllTxHex function
    return await batchAllTxHex(nftsTxs)
  ...
  }catch(error){
    console.log(error)
  }
}

It's crucial to remember that a BatchTx Extrinsic is marked as successful even if it gets interrupted. The blockchain will issue an ExtrinsicSuccess event. A recommended practice is to monitor for a BatchCompleted event and use a findEvent() function to ascertain whether a BatchInterrupted event occurred during the batch. If a BatchCompleted event is present, it indicates that the batch was not interrupted. In the absence of this event, it suggests that the batch was interrupted at some point, and one should review the event list for details.


export const batchTx = async () => {
  try {
    ...
    // we assume the API is initialized and the Keyring has been recovered.
    // We create a first tx and get the hash: a collection without limit
    const signableCollection = await createCollectionTx("BatchCollectionTestings", undefined)
    // We create a second tx with a wrong parameter to interrupt the batch: a collection id that does not exist in the chain for now
    const signableNFT = await createNftTx("create NFT with wrong collection Id to interrupted batch", 0, 1000, false)
    // We batch both hashes in an array []
    const signableBatchTx = await batchTxHex([signableCollection, signableNFT])
    // We sign and submit the tx to get the event list
    const batchedEvents = await submitTxBlocking(signableBatchTx, WaitUntil.BlockInclusion, keyring)
    // We check if the event list has a BatchCompletedEvent
    const isBatchCompleted = batchedEvents.findEvents(BatchCompletedEvent)
    // if the event list is equal to 0 (not BatchCompletedEvent), we provide the BatchInterruptedEvent with the error detail.
    if (isBatchCompleted.length <= 0) {
      return batchedEvents.findEvents(BatchInterruptedEvent)
    }
    // We return the full event list if it contains a BatchCompletedEvent
    return batchedEvents
  } catch (err) {
    console.log(err)
  }
}
// The expected output:
//[
//  BatchInterruptedEvent {
//    raw: Type(2) [Map] {
//      ...
//    },
//    type: 'utility.BatchInterrupted',
//    section: 'utility',
//    method: 'BatchInterrupted',
//    index: 1, // index of the interupted item.
//    dispatchError: { ... },
//    errorType: 'CollectionNotFound',
//    details: 'No Collection was found with that NFT id.'
//  }
//]

Last updated