Bug Report: Exit code 147 (invalid_c5) on TON agentic wallets
Project context
I'm building an autonomous trading agent on the TON blockchain. The architecture:
+-----------------+ HTTP/MCP +------------------+ JSON-RPC +-----------------+
| ton-agent | --------------------> | @ton/mcp | -----------------> | TON mainnet |
| (Python) | tools/call | (Node.js MCP | | blockchain |
| MY strategy | | server) | | |
+-----------------+ +------------------+ +-----------------+
|
v
Agentic Wallet (V5 extension)
address: UQBqdLU...Wy0UD
- Wallet: TON Agentic Wallet (a Wallet V5R1 extension, deployed via the official
agents.ton.org dashboard)
- MCP server:
@ton/mcp@alpha (npm package, repo ton-connect/kit/tree/main/packages/mcp)
- Mode: Agentic wallets mode (default)
- Network: mainnet
- Capital: 8.47 TON + 16.10 USDT (~$33)
All diagnostics, implementation and overall system behavior are correct except for the single on-chain execution step, which fails.
Symptom
All write operations of the MCP (send_ton, send_jetton, send_raw_transaction) fail on-chain with:
- Compute Phase:
Success: true, Exit code: 147 (invalid_c5), VM steps: 99, Gas used: 3902
- Action Phase:
Success: true, Result code: 0, Total actions: 0
The MCP server falsely reports success: true with a valid-looking normalizedHash, but the transaction is a no-op: only the minimum gas (~0.0016 TON) is consumed and no action is executed.
Read operations (get_balance, get_jetton_balance, get_swap_quote, get_transaction_status) work correctly.
Reproduction
Reproducer 1: send_ton self-transfer (simplest possible)
mcp.call_tool('send_ton', {
'toAddress': 'UQBqdLUOb5D_.....TSvr1nPdZ-Wy0UD', # self
'amount': '0.05',
'comment': 'self-test',
})
MCP response (false positive):
{
"success": true,
"message": "Successfully sent 50000000 nanoTON to UQBqdLU...",
"normalizedHash": "0x533f471616d4.....9d9695e2ed4dc0e3038d7db2"
}
Verification via get_transaction_status:
{
"status": "completed",
"totalMessages": 1,
"pendingMessages": 0,
"onchainMessages": 1
}
On-chain reality (Tonviewer): the transaction exists, but Compute Phase Exit code: 147, Action Phase Total actions: 0. No transfer happened.
Reproducer 2: DEX swap via Omniston
# Step 1: get_swap_quote (works)
quote = mcp.call_tool('get_swap_quote', {
'fromToken': 'EQCxE6mUtQ.....Rv7Nw2Id_sDs', # USDT
'toToken': 'TON',
'amount': '2.05',
'slippageBps': 200,
})
# Returns valid quote with messages array
Step 2: send_raw_transaction (silently fails)
mcp.call_tool('send_raw_transaction', {
'messages': quote['transaction']['messages']
})
Identical pattern: MCP returns success: true, the tx has exit code 147 on-chain, no swap is executed.
Reference transactions (mainnet)
All on the same agentic wallet UQBqdLU.....STSvr1nPdZ-Wy0UD:
- Self-
send_ton: 533f471616d4ba.....e2ed4dc0e3038d7db2
send_raw_transaction USDT->TON swap: fb98136a75.....52b42ef6be16aa77fc29423477b
Both visible on Tonviewer as "Unknown" entries with the message "Something happened but we don't [understand]".
Technical diagnosis
Exit code 147 = invalid_c5 is defined in the official Wallet V5 source:
// ton-blockchain/wallet-contract-v5/contracts/wallet_v5.fc
const int error::only_extension_can_change_signature_mode = 146;
const int error::invalid_c5 = 147;
It is thrown by verify_c5_actions when the C5 register (action list cell) built by the contract does not match the expected layout.
Since the agentic wallet extends Wallet V5 and uses the same error constants, this means that the action list serialized by @ton/mcp is rejected by the agentic wallet's compute phase, even though it would presumably be valid for a standard Wallet V5.
Technical hypotheses (in order of plausibility)
-
Extension authentication required.
The agentic wallet may require operator requests to be wrapped with the extn opcode (0x6578746e) instead of signed_external (0x73696e74). The MCP appears to use the latter.
-
is_signature_allowed flag mismatch.
If the agentic deployment sets is_signature_allowed = false, messages signed directly by the operator are rejected: they must come through an extension.
-
Action ordering / encoding.
Wallet V5R1 vs V5Beta differ in action tag size (8-bit vs 32-bit) and in whether extended actions must precede send_msg actions in the OutList.
Without running the wallet's getters (is_signature_allowed, get_extensions, get_public_key), it is hard to pinpoint which of the three is the actual cause, but all three would produce exit code 147.
Impact
- ❌ Cannot send TON from the agentic wallet
- ❌ Cannot send jettons (USDT, etc.)
- ❌ Cannot perform DEX swaps
- ❌ Cannot deploy contracts
- ✅ Read-only operations work fine
The agentic wallet is effectively read-only when accessed through @ton/mcp.
Severity of the false positive
The fact that the MCP returns "success": true with a valid-looking normalizedHash is a separate problem. An autonomous agent built on these primitives will:
- Record the transaction as successful in its local state
- Believe funds were transferred
- Update strategy state accordingly (e.g. decrement available balance, advance cooldowns)
- Diverge from on-chain reality
For autonomous AI agents this is the worst possible failure mode: silent and cumulative.
Things already tried
| Attempt |
Result |
| send_ton (plain TON transfer to self) |
FAIL exit code 147 |
| send_raw_transaction with messages from get_swap_quote |
FAIL exit code 147 |
| Various retries (10 retries on Omniston transient quote failures) |
Quote OK, but swap fails on-chain |
| Wallet config check via agentic_validate_wallet |
OK, wallet has deployedByUser=true, has_operator_private_key=true |
| Reading balances and quotes |
Works perfectly |
| WALLET_VERSION=agentic single-wallet mode with PRIVATE_KEY env |
Not tested: config registry is encrypted, operator key not extractable in plaintext |
| Trying another DEX |
Not tested: even a plain TON transfer fails, the issue is not with the DEX |
Bug Report: Exit code 147 (
invalid_c5) on TON agentic walletsProject context
I'm building an autonomous trading agent on the TON blockchain. The architecture:
agents.ton.orgdashboard)@ton/mcp@alpha(npm package, repoton-connect/kit/tree/main/packages/mcp)All diagnostics, implementation and overall system behavior are correct except for the single on-chain execution step, which fails.
Symptom
All write operations of the MCP (
send_ton,send_jetton,send_raw_transaction) fail on-chain with:Success: true, Exit code: 147 (invalid_c5), VM steps: 99, Gas used: 3902Success: true, Result code: 0, Total actions: 0The MCP server falsely reports
success: truewith a valid-lookingnormalizedHash, but the transaction is a no-op: only the minimum gas (~0.0016 TON) is consumed and no action is executed.Read operations (
get_balance,get_jetton_balance,get_swap_quote,get_transaction_status) work correctly.Reproduction
Reproducer 1: send_ton self-transfer (simplest possible)
MCP response (false positive):
Verification via
get_transaction_status:On-chain reality (Tonviewer): the transaction exists, but
Compute Phase Exit code: 147,Action Phase Total actions: 0. No transfer happened.Reproducer 2: DEX swap via Omniston
Identical pattern: MCP returns
success: true, the tx has exit code 147 on-chain, no swap is executed.Reference transactions (mainnet)
All on the same agentic wallet
UQBqdLU.....STSvr1nPdZ-Wy0UD:send_ton:533f471616d4ba.....e2ed4dc0e3038d7db2send_raw_transactionUSDT->TON swap:fb98136a75.....52b42ef6be16aa77fc29423477bBoth visible on Tonviewer as "Unknown" entries with the message "Something happened but we don't [understand]".
Technical diagnosis
Exit code
147 = invalid_c5is defined in the official Wallet V5 source:It is thrown by
verify_c5_actionswhen the C5 register (action list cell) built by the contract does not match the expected layout.Since the agentic wallet extends Wallet V5 and uses the same error constants, this means that the action list serialized by
@ton/mcpis rejected by the agentic wallet's compute phase, even though it would presumably be valid for a standard Wallet V5.Technical hypotheses (in order of plausibility)
Extension authentication required. The agentic wallet may require operator requests to be wrapped with the
extnopcode (0x6578746e) instead ofsigned_external(0x73696e74). The MCP appears to use the latter.is_signature_allowedflag mismatch. If the agentic deployment setsis_signature_allowed = false, messages signed directly by the operator are rejected: they must come through an extension.Action ordering / encoding. Wallet V5R1 vs V5Beta differ in action tag size (8-bit vs 32-bit) and in whether extended actions must precede
send_msgactions in the OutList.Without running the wallet's getters (
is_signature_allowed,get_extensions,get_public_key), it is hard to pinpoint which of the three is the actual cause, but all three would produce exit code 147.Impact
The agentic wallet is effectively read-only when accessed through
@ton/mcp.Severity of the false positive
The fact that the MCP returns
"success": truewith a valid-lookingnormalizedHashis a separate problem. An autonomous agent built on these primitives will:For autonomous AI agents this is the worst possible failure mode: silent and cumulative.
Things already tried