I’ve been trying to reuse a wallet deleted by DESTROY_ACCOUNT_IF_ZERO
(32) flag. The way I do the transfer:
Imagine we have 2 wallets: A and B.
- We transfer
N1
TON fromA
toB
. E.g. by using a web-based wallet, script, doesn’t matter. B
is uninitialized – it is not on the blockchain yet. With that in mind, we’d like to send all the money fromB
back toA
. For this we’re going to use the attached script.- Now we go ahead and transfer
N2
TON fromA
toB
again. Doesn’t matter how much.
Expected behavior: we get transactions: A->B (N1)
, B->A (all)
, A->B (N2)
; wallet B
has N2
TONs in the end.
Actual behavior: we get transactions A->B (N1)
, B->A (all)
, A->B (N2)
, B->A (all)
; wallet B
has 0
TONs in the end.
The script for B->A (all)
transfer, which causes this behavior:
import TonWeb from 'tonweb';
import tonwebMnemonic from 'tonweb-mnemonic';
const apiKey = "" || undefined;
// WALLET B
const mnemonic = "...";
const walletVersion = "v4R2";
// WALLET A
const toAddress = "...";
const SendMode = {
CARRY_ALL_REMAINING_BALANCE: 128,
CARRY_ALL_REMAINING_INCOMING_VALUE: 64,
DESTROY_ACCOUNT_IF_ZERO: 32,
PAY_GAS_SEPARATELY: 1,
IGNORE_ERRORS: 2,
NONE: 0
}
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
(async () => {
const provider = new TonWeb.HttpProvider('https://toncenter.com/api/v2/jsonRPC', {apiKey});
const WalletClass = TonWeb.Wallets.all[walletVersion];
const mnemonicArray = mnemonic.split(" ");
let { publicKey, secretKey } = await tonwebMnemonic.mnemonicToKeyPair(mnemonicArray);
publicKey = Buffer.from(publicKey);
secretKey = Buffer.from(secretKey);
console.log(`PUBLIC KEY: ${publicKey.toString('hex')}`);
const wallet = new WalletClass(provider, { publicKey });
const seqno = await wallet.methods.seqno().call() || 0;
console.log(`SEQNO: ${seqno}`);
await sleep(2000);
const transferParams = {
secretKey,
toAddress,
amount: 0,
seqno,
sendMode: SendMode.CARRY_ALL_REMAINING_BALANCE | SendMode.IGNORE_ERRORS | SendMode.DESTROY_ACCOUNT_IF_ZERO,
payload: "test bug"
};
console.log(JSON.stringify({...transferParams, secretKey: transferParams.secretKey.toString('hex')}, null, 2));
const response = await wallet.methods.transfer(transferParams).send();
console.log(`transfer sent to blockchain: ${JSON.stringify(response, null, 2)}`);
})();
The strange thing is: if you send A->B (N)
again, it will create a new transfer B->A (all)
again and again automatically. Sometimes it stops at 2 repeats, sometimes at 4.
I use the unbounceable address: UQAPqRlewultl8xHCKGsrenb4PZaQ0QDfPYoK1fwVUODdZRd
.
I also tried sending TON from wallet C
(C->B
). And the money DID stay on B
. BUT once I made a transfer A->B
again, all the money including the TONs sent from C
went to A
automatically!
An example of this bug’s manifestation (is it a bug??) is here:
https://tonviewer.com/EQAySjlsHUY2EEedO5GTenzFvAnR5E-4ptwfeox6OZYnNvGF
This is B
wallet. Only the first message with “test bug” text was sent by the script. The rest of them were sent automatically on any incoming transfer from A
.
In this interaction:
A
isUQAPqRlewultl8xHCKGsrenb4PZaQ0QDfPYoK1fwVUODdZRd
B
isEQAySjlsHUY2EEedO5GTenzFvAnR5E-4ptwfeox6OZYnNvGF
C
isUQBwpXsIVrij8UQ2OpPK2EyeVBrlN6mnOkmThb3k6K-UHZyL
I want to understand, why this happens. Is this intended by TON blockchain developers? Is this not a bug? How to go around this and reuse deleted wallets?