1

Example:

// construct a list of transactions we want to batch
const txs = [
  api.tx.balances.transfer(addrBob, 12345), (1)
  api.tx.balances.transfer(addrEve, 12345), (2)
  api.tx.staking.unbond(12345) (3)
];

// construct the batch and send the transactions
api.tx.utility
  .batch(txs)
  .signAndSend(sender, ({ status }) => {
    if (status.isInBlock) {
      console.log(included in ${status.asInBlock});
    }
});

If transaction (2) failed ( don't have enough balance fee to send anymore). So how can I block all the chain transactions or if don't, how can I handle the error comes out?

Currently, The batchAll method does not respond to any error and the result is, (1), (3) success, and 2 fail.

3 Answers 3

2

Like @Iker mentioned batch_all sends a batch of dispatch calls and atomically executes them. The whole transaction will rollback and fail if any of the calls fail.

This video on the utility pallet may be helpful:

Here is an example for listening for system.ExtrinsicFailed as noted here:

const txs = [
  api.tx.balances.transfer(EVE, 5000000),
  // api.tx.balances.setBalance(EVE, 100000000, 0),
  api.tx.identity.clearIdentity(),
  api.tx.system.remark('hello world'.repeat(10)),
]

await api.tx.utility.batchAll(txs).signAndSend(alice, ({ status, events }) => {
  if (status.isInBlock || status.isFinalized) {
    events
      // find/filter for failed events
      .filter(({ event }) =>
        api.events.system.ExtrinsicFailed.is(event)
      )
      // we know that data for system.ExtrinsicFailed is
      // (DispatchError, DispatchInfo)
      .forEach(({ event: { data: [error, info] } }) => {
        if (error.isModule) {
          // for module errors, we have the section indexed, lookup
          const decoded = api.registry.findMetaError(error.asModule);
          const { docs, method, section } = decoded;

          console.log(`${section}.${method}: ${docs.join(' ')}`);
        } else {
          // Other, CannotLookup, BadOrigin, no extra info
          console.log(error.toString());
        }
      });
  }
});

Output:

identity.NotNamed: Account isn't named.

If you are using sudo then you would listen for the Sudid event as noted here:

const txs = [
  api.tx.balances.forceTransfer(ALICE, BOB, 100),
  // api.tx.balances.transfer(EVE, 5000000),
  api.tx.balances.setBalance(BOB, 1000, 0),
  api.tx.balances.forceTransfer(BOB, EVE, 10000),
  api.tx.system.remark('hello world'.repeat(10)),
]

const unsub = await api.tx.sudo.sudo(api.tx.utility.batchAll(txs)).signAndSend(alice, ({ status, events }) => {
  if (status.isInBlock || status.isFinalized) {
    events
      // We know this tx should result in `Sudid` event.
      .filter(({ event }) =>
        api.events.sudo.Sudid.is(event)
      )
      // We know that `Sudid` returns just a `Result`
      .forEach(({ event : { data: [result] } }) => {
        // Now we look to see if the extrinsic was actually successful or not...
        if (result.isError) {
          let error = result.asError;
          if (error.isModule) {
            // for module errors, we have the section indexed, lookup
            const decoded = api.registry.findMetaError(error.asModule);
            const { docs, name, section } = decoded;

            console.log(`${section}.${name}: ${docs.join(' ')}`);
          } else {
            // Other, CannotLookup, BadOrigin, no extra info
            console.log(error.toString());
          }
        }
      });
    unsub();
  }
});

Output:

balances.InsufficientBalance: Balance too low to send value
8
  • this is done batchAll in the interface. I want to handle errors in code. any example? Commented Apr 5, 2023 at 7:27
  • The video shows an example where there is an error in the batch_all, specifically here. You will get a system.ExtrinsicFailed event with the error of the specific transaction that failed.
    – Bruno
    Commented Apr 5, 2023 at 7:29
  • understood that error showing. But I want to ask to handle the error at codes. Commented Apr 5, 2023 at 7:39
  • Updated with a code example.
    – Bruno
    Commented Apr 5, 2023 at 9:37
  • In your case. Is the method throwing an error and stopping transactions? I do exactly your example but in console.log error on chrome. I don't see any throwing error message Commented Apr 5, 2023 at 10:21
1

If you need atomic execution of all the batched calls in the transaction you have to use the batch_all method. With this call, the whole transaction will rollback and fail if any of the calls failed.

You can check the source code of this dispatchable for more information.

0

I found this example. it helps me to log the error, Transactions are still executed and a few seconds later the console.log is displayed. I tried putting in try-catch but it doesn't jump in catch()

api.tx.balances
  .transfer(recipient, 123)
  .signAndSend(sender, ({ status, events, dispatchError }) => {
    // status would still be set, but in the case of error we can shortcut
    // to just check it (so an error would indicate InBlock or Finalized)
    if (dispatchError) {
      if (dispatchError.isModule) {
        // for module errors, we have the section indexed, lookup
        const decoded = api.registry.findMetaError(dispatchError.asModule);
        const { docs, name, section } = decoded;

        console.log(`${section}.${name}: ${docs.join(' ')}`);
      } else {
        // Other, CannotLookup, BadOrigin, no extra info
        console.log(dispatchError.toString());
      }
    }
  });

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.