Skip to content

Sandbox error when testing DeDust example with USDT jetton-wallet (exit code 9: failed to load library cell) #128

@mysteryon88

Description

@mysteryon88

Description

While testing the DeDust example from the Tact cookbook, I encountered a VM crash when the vault tried to interact with the USDT jetton-wallet.

handling exception code 9: failed to load library cell
default exception handler, terminating vm with exit code 9
"@ton/blueprint": ">=0.40.0",
"@ton/sandbox": ">=0.37.0",

Steps to Reproduce

  1. npm create ton@latest
  2. Then a contract was written
//
// Helper structs described earlier on this page
//

struct SwapStep {
    poolAddress: Address;
    kind: Int as uint1 = 0;
    limit: Int as coins = 0;
    nextStep: Cell?;
}
struct SwapParams {
    deadline: Int as uint32 = 0;
    recipientAddress: Address? = null;
    referralAddress: Address? = null;
    fulfillPayload: Cell? = null;
    rejectPayload: Cell? = null;
}
/// https://docs.dedust.io/reference/tlb-schemes#message-swap
message(0xea06185d) NativeSwap {
    // Unique identifier used to trace transactions across multiple contracts
    // Defaults to 0, which means we don't mark messages to trace their chains
    queryId: Int as uint64 = 0;
    // Toncoin amount for the swap
    amount: Int as coins;
    // Inlined fields of SwapStep struct
    poolAddress: Address;
    kind: Int as uint1 = 0;
    limit: Int as coins = 0;
    nextStep: SwapStep? = null;
    // Set of parameters relevant for the whole swap
    swapParams: SwapParams;
}

/// https://docs.dedust.io/reference/tlb-schemes#message-swap-1
message(0xe3a0d482) JettonSwapPayload {
    // Inlined fields of SwapStep struct
    poolAddress: Address;
    kind: Int as uint1 = 0;
    limit: Int as coins = 0;
    nextStep: SwapStep? = null;

    // Set of parameters relevant for the entire swap
    swapParams: SwapParams;
}

message(0xf8a7ea5) JettonTransfer {
    queryId: Int as uint64;
    amount: Int as coins;
    destination: Address;
    responseDestination: Address;
    customPayload: Cell? = null;
    forwardTonAmount: Int as coins;
    forwardPayload: Cell?; // slightly adjusted
}

message SwapTon {
    swapAmount: Int;
}

message SwapJetton {
    swapAmount: Int;
    targetJettonWalletAddress: Address;
}

contract DeDust {
    receive(swap: SwapTon) {
        // Let's say `swapAmount` is `ton("0.1")`, which is 10000000 nanoToncoins
        send(SendParameters {
            // Address of the TON vault to send the message to
            to: address("EQDa4VOnTYlLvDJ0gZjNYm5PXfSmmtL6Vs6A_CZEtXCNICq_"),
            // Amount to swap plus a trade fee
            value: swap.swapAmount + ton("0.2"),
            body: NativeSwap {
                amount: swap.swapAmount,
                // Address of the swap pool, which is the TON/USDT pair in this case
                // poolAddress: address("EQAvtGe8Nep_XncmQYJrqzWjjdsTaygzL17bvH_8Rjryz1xu"), // DeDust Pool: TONNEL/TON
                poolAddress: address("EQA-X_yo3fzzbDbJ_0bzFWKqtRuZFIRa1sJsveZJ1YpViO3r"), // DeDust Pool: TON/USDT
                // Set of parameters relevant for the whole swap
                swapParams: SwapParams {}, // use defaults
            }.toCell(),
        });
    }

    receive(swap: SwapJetton) {
        send(SendParameters {
            to: swap.targetJettonWalletAddress,
            value: ton("0.3"),
            body: JettonTransfer {
                // Unique identifier used to trace transactions across multiple contracts.
                // Set to 0, which means we don't mark messages to trace their chains.
                queryId: 0,
                // Jetton amount for the swap.
                amount: swap.swapAmount, // NOTE: change to your amount
                // Address of the Jetton vault to send the message to.
                destination: address("EQC8jbJfR7Mu7K5oeyiIoHC3gWLmdCju2pUBucXqmQClB__N"), // DeDust Vault
                // Address to return any exceeding funds.
                responseDestination: myAddress(),
                forwardTonAmount: ton("0.25"),
                forwardPayload: JettonSwapPayload {
                    // Address of the swap pool, which is the TON/USDT pair in this case.
                    poolAddress: address("EQAvtGe8Nep_XncmQYJrqzWjjdsTaygzL17bvH_8Rjryz1xu"), // DeDust Pool: TONNEL/TON
                    // Set of parameters relevant for the entire swap.
                    swapParams: SwapParams {}, // use defaults
                }.toCell(),
            }.toCell(),
        });
    }

    receive() {
        cashback(sender());
    }
}
  1. Tests were implemented
import {
    Blockchain,
    SandboxContract,
    TreasuryContract,
    RemoteBlockchainStorage,
    wrapTonClient4ForRemote,
} from '@ton/sandbox';
import { TonClient4 } from '@ton/ton';
import { Address, fromNano, Sender, toNano } from '@ton/core';
import { DeDust } from '../build/DeDust/DeDust_DeDust';
import '@ton/test-utils';

describe('DeDust', () => {
    let blockchain: Blockchain;
    let deployer: SandboxContract<TreasuryContract>;
    let deDust: SandboxContract<DeDust>;

    beforeEach(async () => {
        blockchain = await Blockchain.create({
            storage: new RemoteBlockchainStorage(
                wrapTonClient4ForRemote(
                    new TonClient4({
                        endpoint: 'https://mainnet-v4.tonhubapi.com',
                    }),
                ),
            ),
        });

        deDust = blockchain.openContract(await DeDust.fromInit());

        deployer = await blockchain.treasury('deployer', {});

        const deployResult = await deDust.send(
            deployer.getSender(),
            {
                value: toNano('0.05'),
            },
            null,
        );

        expect(deployResult.transactions).toHaveTransaction({
            from: deployer.address,
            to: deDust.address,
            deploy: true,
            success: true,
        });
    });

    it('should deploy', async () => {
        console.log('My Balance', fromNano(await deployer.getBalance()));
        console.log('DeDustSwapper', fromNano((await blockchain.getContract(deDust.address)).balance));

        const TxResult = await deDust.send(
            deployer.getSender(),
            {
                value: toNano('1.3'),
            },
            { $$type: 'SwapTon', swapAmount: toNano(1) },
        );

        console.log(TxResult);

        console.log('My Balance', fromNano(await deployer.getBalance()));
        console.log('DeDustSwapper', fromNano((await blockchain.getContract(deDust.address)).balance));
    });
});
  1. Runnpx blueprint test

  2. You can find the error here

console.log(TxResult);

Environment

Windows 10

Logs or Screenshots

   {
          address: 61901089978021766573933745695147471064659099173648288175756929695054453318535n,
          lt: 61872258000011n,
          prevTransactionHash: 8089611070652109801654583336794466648641561177747294017534910868700693763909n,
          prevTransactionLt: 61872258000010n,
          now: 1758716651,
          outMessagesCount: 1,
          oldStatus: 'active',
          endStatus: 'active',
          inMessage: [Object],
          outMessages: [Dictionary],
          totalFees: [Object],
          stateUpdate: [Object],
          description: [Object],
          raw: x{788DAC67CCEADB9CAE6FAAC7118F05C0FA95DF36C2A92E686AC39D96310D0A38700003845C1F5A48B11E28EBF6639BEB6AB2706379E989EC368674F23F1A701B50445C0B4EF17974500003845C1F5A48A68D3E2EB0003461046A6}
           x{E_}
            x{680031551C5DDAA2E8FB5C06780F3727107B28395B1ECA8B3E5DD39AE8E96D71DABB002236B19F33AB6E72B9BEAB1C463C1703EA577CDB0AA4B9A1AB0E7658C43428E1D02BCE9340060E9DB20000708B83EB4914D1A7C5D6C_}
             x{0F8A7EA5000000000000000032B2436800355B48BEA2B7CC3AC4182DF9751CDE2C40E37A03F9AEE3EE8CA115DCBD0E29850006AB6917D456F987588305BF2EA39BC5881C6F407F35DC7DD19422BB97A1C5308810075520}
            x{DF_}
             x{580111B58CF99D5B7395CDF558E231E0B81F52BBE6D85525CD0D5873B2C621A1470F00062AA38BBB545D1F6B80CF01E6E4E20F65072B63D95167CBBA735D1D2DAE3B57502B9DBF400608235A0000708B83EB4918D1A7C5D67FFFFFFF87C53F528000000000000000195921B4001AADA45F515BE61D620C16FCBA8E6F4_}
           x{72AB820549B33D13008C60E8EA86C81686AE2E03D191DB0A37A814EEA86A32393BF8B9C591177C3C6CEE96F7BCD53B92EDCAF33BA63DFF6B3067939A63739A9205}
           x{040902BCE9341060C3500E0181046998208D6A_}
            x{407D0C1C095400000000120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000},
          hash: [Function: hash],
          blockchainLogs: '[ 4][t 0][2025-09-24 12:24:11.633000][transaction.cpp:445]\tunpacking account 88DAC67CCEADB9CAE6FAAC7118F05C0FA95DF36C2A92E686AC39D96310D0A387\n' +
            '[ 4][t 0][2025-09-24 12:24:11.633000][transaction.cpp:278]\tlast_paid=0; cells=0 bits=0\n' +
            '[ 4][t 0][2025-09-24 12:24:11.633000][transaction.cpp:508]\tend of Account.unpack() for 0:88DAC67CCEADB9CAE6FAAC7118F05C0FA95DF36C2A92E686AC39D96310D0A387 (balance = 1799935430627ng ; last_trans_lt = 61872258000010..61872258000011)\n' +
            '[ 4][t 0][2025-09-24 12:24:11.633000][transaction.cpp:4006]\tblock random seed set to 0000000000000000000000000000000000000000000000000000000000000000\n' +
            '[ 4][t 0][2025-09-24 12:24:11.633000][transaction.cpp:1292]\tgas limits: max=1000000, limit=459349, credit=0\n' +
            '[ 4][t 0][2025-09-24 12:24:11.633000][transaction.cpp:1706]\tin_msg_state is null\n' +
            '[ 3][t 0][2025-09-24 12:24:11.633000][transaction.cpp:1785]\tUnknown precompiled contract (code_hash=89468F02C78E570802E39979C8516FC38DF07EA76A48357E0536F2BA7B3EE37B, gas_usage=1000), running VM\n' +
            '[ 4][t 0][2025-09-24 12:24:11.633000][transaction.cpp:1799]\tcreating VM\n' +
            '[ 4][t 0][2025-09-24 12:24:11.633000][transaction.cpp:1417]\tSmartContractInfo initialized with [ 124711402 0 0 1758716651 10000000 61872258000011 31001199375342540328671374741713225991918088502499606102394480502517547827387 [ 1800119170227 (null) ] CS{Cell{026dc0088dac67cceadb9cae6faac7118f05c0fa95df36c2a92e686ac39d96310d0a387000000000000000e11707d6922d8068c520c3f8d340} bits: 1..268; refs: 0..0} C{0BC9F6FFD54A6C031C516C4AD2CD9257D49DA3458F89C12B53F90A548D3BD668} C{89468F02C78E570802E39979C8516FC38DF07EA76A48357E0536F2BA7B3EE37B} [ 183739600 (null) ] 0 (null) [ CS{Cell{004dd06600000000000000000000000080000000000000fa00000000000001f4000000000003d09040} bits: 9..305; refs: 0..0} CS{Cell{0008ffffff11} bits: 0..32; refs: 0..0} CS{Cell{0094d1000000000000006400000000000f4240de000000002710000000000000000f424000000000042c1d80000000000000271000000000002625a00000000005f5e100000000003b9aca00} bits: 0..592; refs: 0..0} CS{Cell{0094d100000000000000640000000000009c40de000000000190000000000000000f424000000000000f4240000000000000271000000000009896800000000005f5e100000000003b9aca00} bits: 0..592; refs: 
0..0} CS{Cell{0042ea000000000098968000000000271000000000000f424000000001800055555555} bits: 0..264; refs: 0..0} CS{Cell{0042ea0000000000061a800000000001900000000000009c4000000001800055555555} bits: 0..264; refs: 0..0} (null) ] 0 1000 [ -1 0 CS{Cell{01b1680031551c5ddaa2e8fb5c06780f3727107b28395b1eca8b3e5dd39ae8e96d71dabb002236b19f33ab6e72b9beab1c463c1703ea577cdb0aa4b9a1ab0e7658c43428e1d02bce9340060e9db20000708b83eb4914d1a7c5d6c0} bits: 4..271; refs: 0..0} 478937 61872258000010 1758716651 183739600 183739600 (null) (null) ] ]\n' +
            '[ 4][t 0][2025-09-24 12:24:11.634000][transaction.cpp:1834]\tstarting VM\n' +
            '[ 4][t 0][2025-09-24 12:24:11.634000][transaction.cpp:1839]\tVM terminated with exit code 9\n' +
            '[ 3][t 0][2025-09-24 12:24:11.634000][transaction.cpp:1861]\tsteps: 2 gas: used=160, max=1000000, limit=1000000, credit=0\n' +
            '[ 3][t 0][2025-09-24 12:24:11.634000][transaction.cpp:1863]\tout_of_gas=false, accepted=true, success=false, time=0.000267s\n' +
            '[ 4][t 0][2025-09-24 12:24:11.634000][transaction.cpp:1898]\tgas fees: 400000 = 26214400 * 1000 /2^16 ; price=26214400; flat rate=[40000 for 100]; remaining balance=1800118770227ng\n',
          vmLogs: 'execute implicit JMPREF\n' +
            'handling exception code 9: failed to load library cell\n' +
            'default exception handler, terminating vm with exit code 9\n',
          debugLogs: '',
          oldStorage: undefined,
          newStorage: undefined,
          outActions: undefined,
          events: [Array],
          parent: [Object],
          children: [Array],
          externals: [],
          mode: 0
        },

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions