Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unhandled Rejection when insufficient balance #6040

Open
3 of 10 tasks
0xmemorygrinder opened this issue Dec 6, 2024 · 3 comments
Open
3 of 10 tasks

Unhandled Rejection when insufficient balance #6040

0xmemorygrinder opened this issue Dec 6, 2024 · 3 comments
Labels
Support Tracks issues or requests related to troubleshooting, answering questions, and user assistance.

Comments

@0xmemorygrinder
Copy link

  • I'm submitting a ...
  • Bug report
  • Feature request
  • Support request
  • Other
  • What is the current behavior and expected behavior?

When submitting a tx with an account that does not have sufficient gas for fee, an error is thrown but it is never catched by the calling functions so it ends up in an unhandled rejection error.
Since nodejs 15, the default behavior when an error like this arise is to exit the process with code 1. In other terms if I submit a transaction with not enough balance, my app crashes without asking anything.
This behavior can be prevented by adding a global error handler and while being hacky, the signAndSend method never triggers the passed callback.

2024-12-06 15:41:45        RPC-CORE: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low
2024-12-06 15:41:45        RPC-CORE: submitAndWatchExtrinsic(extrinsic: Extrinsic): ExtrinsicStatus:: 1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low
/project/node_modules/.pnpm/@polkadot+rpc-provider@10.13.1/node_modules/@polkadot/rpc-provider/cjs/coder/index.js:23
        throw new error_js_1.default(`${code}: ${message}${formatErrorData(data)}`, code, data);
              ^

RpcError: 1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low
    at checkError (/project/node_modules/.pnpm/@polkadot+rpc-provider@10.13.1/node_modules/@polkadot/rpc-provider/cjs/coder/index.js:23:15)
    at RpcCoder.decodeResponse (/project/node_modules/.pnpm/@polkadot+rpc-provider@10.13.1/node_modules/@polkadot/rpc-provider/cjs/coder/index.js:39:9)
    at WsProvider.__internal__onSocketMessageResult (/project/node_modules/.pnpm/@polkadot+rpc-provider@10.13.1/node_modules/@polkadot/rpc-provider/cjs/ws/index.js:413:51)
    at WebSocket.__internal__onSocketMessage (/project/node_modules/.pnpm/@polkadot+rpc-provider@10.13.1/node_modules/@polkadot/rpc-provider/cjs/ws/index.js:402:20)
    at callListener (/project/node_modules/.pnpm/ws@8.18.0/node_modules/ws/lib/event-target.js:290:14)
    at WebSocket.onMessage (/project/node_modules/.pnpm/ws@8.18.0/node_modules/ws/lib/event-target.js:209:9)
    at WebSocket.emit (node:events:519:28)
    at Receiver.receiverOnMessage (/project/node_modules/.pnpm/ws@8.18.0/node_modules/ws/lib/websocket.js:1220:20)
    at Receiver.emit (node:events:519:28)
    at Receiver.dataMessage (/project/node_modules/.pnpm/ws@8.18.0/node_modules/ws/lib/receiver.js:596:14)

Node.js v20.17.0

The expected behavior is to catch correctly errors and have a correct callback trigger with the error inside.

  • What is the motivation for changing the behavior?

The app crashing on a so trivial error should be a pretty straightforward motivation.

  • Please tell us about your environment:
  • Version:

  • Environment:

    • Node.js
    • Browser
    • Other (limited support for other environments)
  • Language:

    • JavaScript
    • TypeScript: 5.6.3
    • Other
@TarikGul TarikGul added the Support Tracks issues or requests related to troubleshooting, answering questions, and user assistance. label Dec 9, 2024
@TarikGul
Copy link
Member

TarikGul commented Dec 9, 2024

Hey, do you mind posting a short example that would demonstrate the above?

@0xmemorygrinder
Copy link
Author

Sure, here is the code I use in my app (from the repository examples)

const api = await initialize(AVAIL_URL);
const account = getKeyringFromSeed(AVAIL_MNEMONIC);

const data = AbiCoder.defaultAbiCoder().encode(['string[]'], [DATA_TO_PUSH]);

const txResult: any = await new Promise((res) => {
  api.tx.dataAvailability.submitData(data).signAndSend(
    account,
    {
      // @ts-expect-error Avail uses snake_case for app id
      app_id: AVAIL_APP_ID,
    },
    (result: any) => {
      if (result.isFinalized || result.isError) {
        res(result);
      }
    },
  );
});

@valentinfernandez1
Copy link
Contributor

valentinfernandez1 commented Jan 24, 2025

@0xmemorygrinder Can you expand on your issue 🙏🏻. It seems like just wrapping your transaction call in a try catch should be enough to successfully handle an error triggered by a failed transaction. Here's a simple example:

import { ApiPromise, Keyring, WsProvider } from "@polkadot/api";
import { AccId32 } from "./dev-accounts.json";
const CHAIN_ENDPOINT = "ws://127.0.0.1:9988";

const main = async () => {
  const api = await ApiPromise.create({
    provider: new WsProvider(CHAIN_ENDPOINT),
  });

  await api.isReady;

  const keyring = new Keyring({ type: "sr25519" });
  const unfundedSender = keyring.addFromUri("//ZeroBalanceSeed");

  try {
    // This will fail since the sender has no funds
    const res = await api.tx.balances
      .transferKeepAlive(AccId32.BOB, 1000000000)
      .signAndSend(unfundedSender);
    console.log(res.toHuman());
  } catch (error) {
    console.log("Handle the error correctly:", error);
  }

  console.log("--- Continue no problem after error ---");
  const alice = keyring.addFromUri("//Alice");

  try {
    //Should succed
    const res = await api.tx.balances
      .transferKeepAlive(AccId32.BOB, 1000000000)
      .signAndSend(alice);
    console.log("Succesful:", res.toHuman());
  } catch (error) {
    console.log(error);
  }
};

main();

Output logs

2025-01-24 09:34:57        RPC-CORE: submitExtrinsic(extrinsic: Extrinsic): Hash:: 1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low
Handle the error correctly: RpcError: 1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low
    at checkError (.....
--- Continue no problem after error ---
Succesful: 0xac3ec7bd1cdababe69fc086fb134c3057541589ee230e326d966677c598ecb19

As you can see it was able to handle the error and the continue with the execution. Is there something I'm missing from your example? Please feel free to provide more details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Support Tracks issues or requests related to troubleshooting, answering questions, and user assistance.
Projects
None yet
Development

No branches or pull requests

3 participants