akegaviar / ton-foo

MIT License
0 stars 0 forks source link

How to send bounceable transaction? OR transaction spent the sender's entire balance! #521

Open akegaviar opened 4 months ago

akegaviar commented 4 months ago

How to send bounceable transfer of native TON?

According to the documentation:

To send bounceable transfer it is required to set bounce flag in internal message and use sending mode +16.

+16 | In the case of action fail - bounce transaction

It is uninitialized wallet: https://testnet.tonviewer.com/EQAfs3mJctSyXlJpR89j6h1T7fYJ_nBt8hGbfkDUaET7x9p8

Code sample:

import { WalletContractV4, TonClient, internal } from '@ton/ton';

const client = new TonClient({
  endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
});

const walletContract = client.open(wallet);
const seqno = await walletContract.getSeqno();

const transfer = await walletContract.createTransfer({
  secretKey: key.secretKey,
  seqno: seqno,
  sendMode: 16,
  messages: [
    internal({
      to: 'EQAfs3mJctSyXlJpR89j6h1T7fYJ_nBt8hGbfkDUaET7x9p8',
      value: 12345,
      bounce: true,
      // sender is fresh wallet so init it
      init: wallet.init,
    })
  ],
});

await walletContract.send(transfer);

Expected behaviour Transaction amount is returned to sender minus fee

Actual bahaviour An infinite number of attempts has spent the sender's entire balance https://testnet.tonviewer.com/0QA3tr_6AZK9qMQy46a7ULtriizI7iXeiPufNxib4a7b6eU8

Answer

TLDR: For external messages to wallets, don't set the +16 flag, instead set the +2 flag.

The meaning of +16 flag: If there was an error in processing the action, bounce the message in addition to rolling back the transaction. This has no use in external messages, because there is no sender to receive the bounced message.

The meaning of +2 flag: If there was an error in processing the action, don't rollback the transaction and ignore it. This is very important in external messages to wallets.

Wallets first check the signature and when parameters are valid, they ACCEPT the message, and then try to process input actions. If any action fails and it's not ignored, the transaction will rollback, but the wallet will pay for the gas since it has already ACCEPTED the message.

So it's critical to not fail after the message is ACCEPTED. This is why you have to set +2 flag in external messages to wallets.


Original