Skip to main content
What you’ll be able to do
  • Create and fund a smart account.
  • Approve and execute transactions with one or multiple signers.
  • Update the account’s signers and approval requirements.
MetalAccount is Metal’s smart account. It holds tokens at its own address and executes calls approved by its signers. The calls, nonce and expiry form an operation. Each signer has a weight. This guide uses operations approved by signatures whose combined weight meets the account’s approval threshold. Any relayer may submit the approved operation in a transaction and pay its fee. This guide uses ordinary EVM signing accounts in two configurations: a single signer with weight one and threshold one, or three signers with weight one and threshold two. The second configuration requires any two distinct signers to approve an operation.

Configure the factory and signers

Install public packages with pnpm add @metalntwx/metal-ts@0.3.2 viem@2.57.7. Use relayerWallet to submit transactions and pay gas. The wallet clients walletA, walletB and walletC represent the three signers that approve operations. Keep the signers’ keys separate and request each signature independently. Maintain access to enough signers to meet the approval threshold. Before discarding a temporary test signer, use the current signers to approve its removal and set a threshold the remaining signers can meet. Verify that change at finality before discarding the key. On Metal Testnet, the factory recorded by @metalntwx/metal-pay@0.3.4 is 0x3dbED5DebA965A639bB0Fd40BE96b97922070FA8. Verify factory code and implementation() against the current network configuration before creating an account.
Each ordinary signer is encoded as its 20-byte address. The factory uses the initial signer array, including its order, to derive the account address. Save the exact initial configuration and predicted address. For a single-signer account, use [signers[0]], [1n] and 1n instead. Every weight must be positive and the threshold must be reachable. Factory creation is permissionless and idempotent for the exact configuration. An existing account may have changed its signers since creation, so always inspect its current configuration.

Create and fund the account

Use the relayer to call createAccount(signers, weights, threshold). Simulate and estimate this call using Estimate and record fees. Sign it with signMip20Contract as in Prepare a transfer, substituting the factory address, ABI, function and arguments above. Save the signed attempt before sending it. Verify successful execution, the receipt’s block hash and finality. For a new account, AccountCreated must name the predicted address. If the account already existed, the factory returns its address without emitting another creation event. Verify code at that address, getSignerCount(), getSigners(0, count), each signerWeight and threshold() against the intended current configuration. Fund accountAddress with a small MIP20 transfer using Direct payment. The MetalAccount supplies the payment amount for its outgoing calls. Fund the relayer’s signing account separately so it can pay transaction fees from its balance in the gas token.

Build the operation

This operation transfers amount of the MIP20 token from the MetalAccount to recipient. Verify the token address and convert the amount to base units using the direct-payment guide. Check the MetalAccount’s spendable balance before requesting approval.
The mode is ERC-7821 batch execution with default revert behavior. Each call’s native value is zero because the MIP20 function transfers the token amount. A nonce combines a 192-bit key in the high bits and a 64-bit sequence. The call above reads the nonce for key zero. Coordinate operation preparation for each key so requests receive distinct sequence numbers.

Collect approvals and submit

The EIP-712 domain uses the MetalAccount as verifyingContract. Review the target, decoded calldata, amount, recipient and nonce before requesting signatures. Compare the locally computed digest with the account’s executeDigest.
validUntil is the latest block timestamp at which the approval can execute. This example allows one hour. Save the deadline with the operation; extending it requires new signatures. For the single-signer configuration, encode that signer’s address and signature. Each signer contributes its weight once. To use other ERC-7913 signer types, provide their verifier and signature encoding. A contract signer requires ERC-1271 signature validation, including ERC-7739 domain binding when the signer is another MetalAccount. Estimate operation for the relayer, sign the outer transaction with signMip20Contract, and save its bytes and hash before submission. Save the operation bytes, nonce, deadline, approvals and expected target effect in the same durable operation record. A changed operation requires fresh approvals. Require Executed(nonce) from the MetalAccount and verify the expected result of its calls. For this transfer, verify the token transfer from accountAddress to recipient, the receipt’s block hash and finality using Verify a finalized transfer. Read the nonce again and require the sequence to advance once.

Change the signers and threshold

Administration functions accept calls only from the account itself. Encode an ERC-7821 batch whose target is accountAddress and whose calldata calls addSigners, removeSigners, setSignerWeights or setThreshold. Approve and submit that batch through the same executeSigned procedure with the required signing weight under the account’s current threshold and a fresh nonce. To replace one signer in a two-of-three account, batch addSigners([newSigner]) followed by removeSigners([oldSigner]). A newly added signer has weight one. Keep the threshold at two. To change weights, call setSignerWeights before raising the threshold. Lower the threshold before a removal that would make it unreachable. All calls in the batch revert together if any step fails. After finality, read back the signer list, weights and threshold. Confirm that the replacement can approve a new operation and the removed signer no longer contributes weight. Signer changes preserve the account’s address and funds.

Schedule submission

An approved executeSigned operation runs when its transaction is included. To submit it later, use the network contract scheduler, on a network that has one; Metal Testnet does not have the scheduler yet. Set the approval’s validUntil to cover the intended execution window and reconcile its nonce before submitting the same operation through another path.

Test and recover

Simulate duplicate signatures, insufficient signing weight, changed calldata, wrong domain, an expired approval and a direct administrative call from the relayer. They must fail without changing the target’s state. Replaying an executed nonce must also fail. Verify both the one-signer and two-of-three configurations before changing signer weights or approval thresholds. After an uncertain submission, use the saved outer transaction hash and account nonce to investigate the original operation. If the nonce has advanced, find its execution and verify the intended result before authorizing another payment. Follow Recover an uncertain submission to resolve the saved attempt.