toncenter / tonweb

JavaScript SDK for TON (The Open Network)
MIT License
432 stars 107 forks source link

[Question] How to accurately calculate the transfer fee? #124

Open mahnunchik opened 4 months ago

mahnunchik commented 4 months ago

Hello, I've faced with the issue that estimated fee doesn't math the real fee paid for the transfer.


const fee = await wallet.methods.transfer({
  secretKey: key.secretKey,
  toAddress: '0QB_kdbjnUbUvL0x8RjwikMOx19XZ_BKXFIiFTrrCIWLXX_u',
  amount: 100,
  seqno,
  payload: 'Hello',
}).estimateFee();

console.log('estimate:', fee);

await wallet.methods.transfer({
  secretKey: key.secretKey,
  toAddress: '0QB_kdbjnUbUvL0x8RjwikMOx19XZ_BKXFIiFTrrCIWLXX_u',
  amount: 100,
  seqno,
  payload: 'Hello',
}).send();

Estimation output

{
  '@type': 'query.fees',
  source_fees: {
    '@type': 'fees',
    in_fwd_fee: 1564000,
    storage_fee: 108,
    gas_fee: 3308000,
    fwd_fee: 1000000
  },
  destination_fees: [],
  '@extra': '1707860854.2520125:2:0.9797682220993219'
}

Sum of storage_fee + in_fwd_fee + fwd_fee + gas_fee equals 5872108 which is 2 gram less then real fee paid for the transaction https://testnet.tonscan.org/tx/2xRWxV-7sIxMWpT8xmLGYgc5Z8YOk93GZVURJzw2Ro0= (0,00587211 TON = 5872110).

How to accurately calculate the transfer fee?

mahnunchik commented 4 months ago

Fee estimation shortage may differ from 2 to 100 grams, but always less then real fee.

di-sukharev commented 4 months ago

same, here is the code piece:

  const estimatedFee: {
    "@type": "query.fees";
    source_fees: {
      "@type": "fees";
      in_fwd_fee: number;
      storage_fee: number;
      gas_fee: number;
      fwd_fee: number;
    };
    destination_fees: [];
    "@extra": string;
  } = await wallet.methods
    .transfer({
      secretKey: keyPair.secretKey,
      toAddress,
      amount: amountInNanoTon,
      seqno,
      payload,
    })
    .estimateFee();

then i sum it all up:

  const allFees = [
    estimatedFee.source_fees.fwd_fee,
    estimatedFee.source_fees.storage_fee,
    estimatedFee.source_fees.gas_fee,
    estimatedFee.source_fees.in_fwd_fee,
  ].reduce((acc, curr) => new BN(curr).add(acc), new BN(0));

eventually such a test fails:

      const targetWalletBalanceAfterWithdrawal = await tonweb.getBalance(
        targetWallet.address!
      );

      expect(new BN(targetWalletBalanceAfterWithdrawal).toString()).toBe(
        withdrawalAmountAfterAllFees
      );

Error:

error: expect(received).toBe(expected)

Expected: "112416255"
Received: "112316255"

i calculate amountToWithdrawInNanoTon like this new BN(amount).sub(allFees)

di-sukharev commented 4 months ago

or this error:

error: expect(received).toBe(expected)

Expected: "96813476"
Received: "96713476"

its always off by 100000

mahnunchik commented 4 months ago

Related issue: https://github.com/ton-org/ton/issues/23

di-sukharev commented 4 months ago

it's always off by 100000, it's driving me crazy:

const targetWalletBalanceBeforeWithdrawal = await tonweb.getBalance(
  targetWallet.address!
);

// this works fine
expect(new BN(targetWalletBalanceBeforeWithdrawal).toString()).toBe(
  new BN(0).toString()
);

const targetWalletBalanceAfterWithdrawal = await tonweb.getBalance(
  targetWallet.address!
);

// for some reason the balance is 100000 nano tons off!
expect(new BN(targetWalletBalanceAfterWithdrawal).toString()).toBe(
  withdrawalAmountAfterAllFees
);

error: expect(received).toBe(expected)

Expected: "503042562"
Received: "502942562"

here is the amountInNanoTon: "508872563" i have, here is the calculated fee: allFees: "5830001", then i subtract the allFees from the amountInNanoTon and get this finalAmountInNanoTon: "503042562", then i check the wallet balance and it's 502942562 which is less for 100000 than expected

di-sukharev commented 4 months ago

here are the fees from transfer.estimateFee() method and calculation example:

FEES {
  estimatedFee: {
    "@type": "query.fees",
    source_fees: {
      "@type": "fees",
      in_fwd_fee: 1836000,
      storage_fee: 1,
      gas_fee: 2994000,
      fwd_fee: 1000000,
    },
    destination_fees: [],
    "@extra": "1708581237.5574996:5:0.014051555176774921",
  },
  allFees: "5830001",
}

here is the finalAmountInNanoTon: "499013448" which i send to the wallet, then i check the wallet balance and it's:

Expected: "499013448"
Received: "498913448"
di-sukharev commented 4 months ago

ok, in my case the missing 100000 was gas fee for the receiver wallet. The expected amount-fees correctly lands to the receiver wallet, but then the gas fee of 100000 is subtracted, so all good for me

895268679long commented 3 months ago

May I ask how to convert mnemonics into public and private keys?

Nguyen-Sy commented 3 months ago

@895268679long import * as tonMnemonic from "tonweb-mnemonic"; const mnemonics = ["your mnemonics"] const keyPair = await tonMnemonic.mnemonicToKeyPair(mnemonics as string[]);