Any guidance on how to call my psp22 approve function from the front end ? This is currently how I'm doing it but it doesn't seem to give increased allowance (although its successful) :

import { ContractPromise } from '@polkadot/api-contract';
import { web3Accounts, web3Enable, web3FromSource, isWeb3Injected } from '@polkadot/extension-dapp';
import abi from './alephcontract.json';
import abi_psp22 from './psp22.json';
const { ApiPromise, WsProvider } = require('@polkadot/api');
const { BN } = require('@polkadot/util');

const batchApprove = async (tokens, recipients, amounts) => {
    try {

      if (recipients.length === 0 || amounts.length === 0 || tokens.length === 0) {
        throw new Error('recipients and amounts must be non-empty');

      if (recipients.length !== amounts.length || recipients.length !== tokens.length) {
        throw new Error('recipients and amounts must be the same length');

      const wsProvider = new WsProvider('wss://ws.test.azero.dev');
      const api = await ApiPromise.create({ provider: wsProvider });

      const injector = await web3FromSource('polkadot-js');
      const allAccounts = await web3Accounts();

      let txs = [];
      const AlephcontractAddress = '5cJdgjhx1234567890...';

      const formattedAmounts = amounts.map((amount, index) => {
        const formatted = new BN(amount).mul(new BN(10).pow(new BN(12)));
        return formatted.toString();

      amounts.map(async (amount, index) => {

        const Contract = new ContractPromise(api, abi_psp22, tokens[index]);

        txs.push(await Contract.tx['psp22::approve'](tokens[index], AlephcontractAddress, amount))


      // construct the batch and send the transactions
      await api.tx.utility
        .signAndSend(allAccounts[0].address, async ({ status }) => {
          if (status.isInBlock) {
                console.log(`included in ${status}`);
                 //perform a transfer


    } catch (error) {

But the allowance remains at 0 when I check afterwards.

PS : I am using polkadot.js package for the interactions

  • Please provide whole code or the link to github. What is the difference between tokenAddress in ContractPromise and "tokensAddress" you are using in Contract.tx?
    – Maario
    Jul 19 at 8:46
  • @Maario The question context has been updated
    – 0xD1x0n
    Jul 19 at 13:23

3 Answers 3


The way I approach such error is in 2 steps.

  1. Make sure contract works.

Use Contracts-UI, deploy the contract and check that approve/allowance work as you expected.

  1. Dry-run Tx

Before sending Tx, first send query for the same ink! message. That will dry-run your approve message and you can capture (console.log) the error if there is any

const result = await Contract.query['psp22::approve'](tokens[index], AlephcontractAddress, amount))

BTW, with the approve it is most likely that you use wrong signing address to give the approval


it looks like you're not using await, you can also check how we've implemented it in the typechain-polkadot

  • Appreciate the help! I will probably use this for production build. I tried putting await before the call but it didn't seem to work. I'm updating my question with the full context
    – 0xD1x0n
    Jul 19 at 13:10
  • The problem is that you are making an extrinsic without sending it, check out this Jul 19 at 16:30
  • Am I not doing that here : await api.tx.utility .batch(txs) .signAndSend(...) ?
    – 0xD1x0n
    Jul 19 at 18:06

I fixed it by simply specifying the gasLimit.

const result = Contract.tx['psp22::approve']({
  gasLimit: api.createType('WeightV2', {
    refTime: 99999999999,
    proofSize: 99999999999,
  , AlephcontractAddress, api.createType("Balance", 100));

Your Answer

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

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