Skip to content

feat(node): accept a CLT transfer signed by MetaMask - #26

Merged
MehranMazhar merged 1 commit into
mainfrom
claude/project-thread-udrihq
Oct 9, 2026
Merged

MehranMazhar merged 1 commit into
mainfrom
claude/project-thread-udrihq

Conversation

@MehranMazhar

Copy link
Copy Markdown
Member

Requested by Mehran · project thread

📋 Description

Before: MetaMask shows a CLT balance, but the node rejects anything a wallet can send, because a wallet only sends by signing a legacy Ethereum transaction.

After: the node accepts that signed transaction as a new type, WalletTransfer (RLP tag 10), and applies it exactly like a Transfer with the flat tx_fee. Nothing changes until the chain switches it on.

How:

  • transactions/wallet_transfer.rs decodes the raw EIP-155 legacy transaction, recovers from, and keeps every field the signature covers (to, value, gas_price, gas_limit, wallet_chain_id), so any node can rebuild the signed bytes and verify them. Clutch nonce = wallet nonce + 1. Value = wei / 10^12; more than 6 decimals is refused, never rounded. Refused: data, contract creation, typed (EIP-1559) txs, no chain id, high s, non-canonical encoding.
  • The tx hash is the Ethereum hash, so the wallet, the explorer and lookups show one hash. Only its own EIP-155 signature verifies it (the three existing schemes do not apply).
  • gas_price × gas_limit must cover tx_fee in wei; wallet_chain_id must equal the node's.
  • New RPC: send_wallet_transaction (raw hex → {hash}) and get_transaction_by_hash ({transaction, block_index, block_hash}, block fields null while pooled).
  • Consensus switch: config wallet_chain_id + wallet_transfers_from_block (both or neither; the node refuses to start with one). Unset, or below that block, the type is refused in the pool and in blocks. Every validator must carry the same values before the block. The rule sits on Database because every validation path holds it.

🔗 Related Issues

  • Relates to clutch-hub (the /rpc side), clutch-deploy (stage config), clutch-explorer, clutch-docs PRs on the same branch name.

🎯 Type of Change

  • ✨ New feature
  • 💥 Breaking change (consensus: a validator without this build and rule refuses blocks carrying a WalletTransfer once it is switched on)

🧪 Testing

  • Unit tests pass (cargo test -- --test-threads=1, whole suite green)
  • Manual testing completed: local single-validator node + local Hub; ethers 6.13.4 wallet.sendTransaction of 1.25 CLT through /rpc returned a receipt with status 1, fee 0.001, balances moved; 1 wei refused with the 6-decimals message
  • New tests added: tests/wallet_transfer.rs (fixtures signed by ethers, pool → block → lookup by hash, rule off / before activation / other wallet chain id / tampered / insufficient balance, and a peer without the rule refusing the block after an RLP round trip) plus unit tests in wallet_transfer.rs

🔒 Security Checklist

  • No private keys or secrets in code (fixtures use Hardhat's public test key)
  • Input validation implemented
  • Cryptographic functions used correctly (EIP-155 sighash, low-s, replay bound to wallet_chain_id)
  • No introduction of centralization points

✅ Checklist

  • I have performed a self-review of my code
  • My changes generate no new warnings
  • New and existing unit tests pass locally with my changes

Merging moves the stage node pin; with no rule in config the stage chain behaves exactly as today. Mainnet is untouched (its pins move by hand).

🤖 Generated with Claude Code

https://claude.ai/code/session_0152exeqGYmUeykE5Z5AsHtm


Generated by Claude Code

…ransaction

A wallet can only send a coin by signing a legacy Ethereum transaction (EIP-155).
New type WalletTransfer (RLP tag 10) keeps every field that signature covers, so any
node can rebuild the signed bytes and check them; its hash is the Ethereum hash.
New RPC send_wallet_transaction and get_transaction_by_hash, for the Hub's /rpc.

Consensus change, off unless wallet_chain_id and wallet_transfers_from_block are set:
without them, or below that block, the type is refused in the pool and in blocks.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_0152exeqGYmUeykE5Z5AsHtm
@MehranMazhar MehranMazhar self-assigned this Oct 9, 2026
@MehranMazhar
MehranMazhar marked this pull request as ready for review October 9, 2026 11:34
@MehranMazhar
MehranMazhar merged commit aa4159f into main Oct 9, 2026
5 checks passed
@MehranMazhar
MehranMazhar deleted the claude/project-thread-udrihq branch October 9, 2026 11:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants