frametx
frametx is the reference implementation: a Go command-line tool that generates
keys, derives counterfactual addresses, and builds, signs, and submits frame
transactions. It emits stable JSON on stdout, which makes it easy to script and
easy to diff.
It is also the oracle the other SDKs are tested against. viem-8141 and
web3-8141 are both differentially tested against frametx, so three
independent implementations must produce byte-identical encodings.
Commands
Section titled “Commands”| Command | Purpose |
|---|---|
keygen |
Generate an ML-DSA keypair. |
address |
Derive a counterfactual account address, offline. |
send |
Build, sign, and submit a spend — with -deploy for the first send. |
rotate |
Rotate a v2 account’s keys using the backup key. |
account / account2 |
Inspect account material for v1 / v2 accounts. |
eoa |
Build a frame transaction signed by a classical secp256k1 key. |
aux |
The witness-segregation reference verifier. |
There is deliberately no deploy command. Accounts are counterfactual, and deployment happens as part of the first send.
Generate a key
Section titled “Generate a key”frametx keygen -variant mldsa65{ "scheme": "ml-dsa", "variant": "mldsa65", "seed": "0x…", "publicKeyKeccak": "0x…"}The 32-byte seed is the secret key. Everything else re-derives from it.
-variant mldsa44 selects the cheaper parameter set (no Secure Enclave
support).
Derive an address
Section titled “Derive an address”frametx address -type v2 \ -activeseed 0xACTIVE \ -backupseed 0xBACKUP-type is v2 (rotatable, recommended), fixed65, or fixed44. Add
-index N to derive additional accounts from the same keys.
For hardware signers that never reveal a secret, pass the public key directly
with -activepk 0x<1952 bytes> — that is all a Secure Enclave will give you.
This command performs no network access.
First send
Section titled “First send”The first transaction from an account materialises it:
frametx send -deploy -accounttype v2 -variant mldsa65 \ -seed 0xACTIVE -backupseed 0xBACKUP \ -recipient 0xRECIPIENT -value 4000 -nonce 0Fund the counterfactual address first, and make sure that funding transaction has been mined — admission reads the payer’s balance from head state.
Ordinary spend
Section titled “Ordinary spend”frametx send -variant mldsa65 \ -seed 0xACTIVE -sender 0xACCOUNT \ -nonce 5 -recipient 0xRECIPIENT -value 100000 \ -feecap 2000000000Read the nonce from the chain — a v2 account’s nonce is 3 after its first send, and rotations advance it by 2.
Rotate
Section titled “Rotate”frametx rotate -sender 0xACCOUNT -nonce N \ -backupseed 0xOLD_BACKUP \ -newactiveseed 0xNEW_ACTIVE \ -newbackupseed 0xNEW_BACKUPSigned by the backup key. See Rotate a key for what this does and why the active key cannot do it.
Variants that take public keys rather than seeds — -newactivepk,
-newbackuppkhash, -backuppk — exist for hardware-backed and
split-custody flows.
frametx historically defaults to a 1 gwei tip. Frost is
fee-blind, so that tip buys nothing; pass
-tipcap 0 if you care. This is the one field where frametx output and the
other SDKs’ builders differ by default.
End-to-end drill
Section titled “End-to-end drill”The repository ships e2e-rotate-drill.sh, a shell script that walks the entire
account lifecycle against a live RPC endpoint using frametx, curl, and jq:
- derive the counterfactual address offline and assert
eth_getCodeis empty; - fund it;
- self-deploying first send, asserting nonce 3 and both storage slots written;
- negative case — a corrupted signature refused at the gate;
- rotation via the backup key;
- assert the old active key is rejected, the new one spends, and the old backup is consumed.
This is the most complete worked example of the account lifecycle that exists, and it runs on a schedule against the live network.
Relationship to the other SDKs
Section titled “Relationship to the other SDKs”Use frametx when you want a reference answer: a canonical encoding to compare
against, or a quick manual check without writing code. Use
viem-8141 or
web3-8141 to build applications.