# TON Highload V3 - msg init

By [zoie](https://paragraph.com/@zoie) · 2025-04-01

---

最近在做ton上的代付Gas项目，使用highload v3钱包帮用户交易代付Gas。

记录一个遇到的问题。

当用户钱包未部署时，需要进行部署。 构造的msg大约是

                const signedCell = Cell.fromBoc(Buffer.from(sig, 'base64'))[0]；
                const message = loadMessage(signedCell.asSlice())
                body = message.body;
                stateInit = message.init;    
    
    
                msg = internal({
                    to: Address.parse(address),
                    value: BigInt(toNano(amount)),
                    bounce: bounce,
                    body: body,
                    init: stateInit
                })
    

交易报错, 在浏览器上看到以下信息

    Compute Phase
    Success:
    true
    Exit code:
    37
    Vm steps:
    151
    Gas used:
    5562
    

看到exit code为37，搜索时搜到了vm code, **Action Phase = 37** 表示账户余额不足。

感觉不太对，是compute 时exit的，应该不是 **Action Phase = 37** 。

一番挣扎后，猜想是否是合约highload里的错误码，OK，方向正确，被我撞到了。

[https://github.com/ton-blockchain/highload-wallet-contract-v3/blob/main/contracts/highload-wallet-v3.func#L169C77-L169C87](https://github.com/ton-blockchain/highload-wallet-contract-v3/blob/main/contracts/highload-wallet-v3.func#L169C77-L169C87)

    const int error::invalid_message_to_send = 37;
    
    // () recv_external(slice msg_body) impure 里
    throw_if(error::invalid_message_to_send, maybe_state_init); ;; throw if state-init included (state-init not supported)
    

external msg里不让带init，一带就会报37。

啊.. 看到这里是找到问题了，但是我的功能要怎么实现呢？

于是再去翻了下[TON文档](https://docs.ton.org/v3/documentation/smart-contracts/contracts-specs/highload-wallet), 文档里提到

Highload v3 will always store the query ID (replay protection) once all the checks pass, however a message may not be sent due to some conditions, including but not limited to:

*   **containing state init** (such messages, if required, may be sent using the special op code to set the action cell after an internal message from Highload wallet to itself)
    
*   not enough balance
    
*   invalid message structure (that includes external out messages - only internal messages may be sent straight from the external message)
    

文档里提供了思路 => set the action cell after an internal message

external-in 的msg 先是调自己，然后再从internal调出去，internal里没有限制不让包含state init。

msg由internal变成action。就完全可以了，嘿嘿

                const action = {
                    type: 'sendMsg',
                    mode: SendMode.PAY_GAS_SEPARATELY,
                    outMsg: internal({
                        to: Address.parse(address),
                        value: BigInt(toNano(amount)),
                        body: body,
                        init: stateInit ?? stateInit,
                        bounce: true
                    })
                }
                const msg = new HighloadWalletV3(Address.parse(from)).packActions([action], toNano(amount),  HighloadQueryId.fromQueryId(BigInt(queryId)));
            
    

事后分析感觉还挺简单的，中间一直怀疑37 code是不是哪里没钱… 耽误了蛮久

---

*Originally published on [zoie](https://paragraph.com/@zoie/ton-highload-v3-msg-init)*
