What is the Intent Hash?
The intent hash is a keccak256 digest of canonical transaction parameters. Both the SDK (client-side) and the Mandate API (server-side) compute it independently from the same inputs. If the two hashes don’t match, the API rejects the request, and the envelope verifier flags the discrepancy. This mechanism ensures the server and your agent agree on exactly what transaction will be signed and broadcast. It prevents tampering, replay attacks, and accidental parameter drift between validation and signing.Canonical String Format
The hash is computed over a pipe-delimited string of ten fields, in this exact order:toandcalldataare lowercased before joining.txTypedefaults to2(EIP-1559) if not specified.accessListis serialized withJSON.stringify(). An empty list produces[].- The final string is UTF-8 encoded, then hashed with keccak256.
SDK Function
The SDK exportscomputeIntentHash for custom signing flows:
|, lowercases to and calldata, and returns the keccak256 hash as a hex string.
HashInput Interface
| Field | Type | Required | Description |
|---|---|---|---|
chainId | number | Yes | Chain ID (e.g. 84532 for Base Sepolia) |
nonce | number | Yes | Sender’s current transaction nonce |
to | `0x${string}` | Yes | Destination address (lowercased in the hash) |
calldata | `0x${string}` | Yes | Transaction data (lowercased in the hash). Use 0x for native transfers. |
valueWei | string | Yes | Native token value in wei (use "0" for ERC20 transfers) |
gasLimit | string | Yes | Gas limit for the transaction |
maxFeePerGas | string | Yes | EIP-1559 max fee per gas in wei |
maxPriorityFeePerGas | string | Yes | EIP-1559 max priority fee per gas in wei |
txType | number | No | Transaction type. Defaults to 2 (EIP-1559). |
accessList | unknown[] | No | EIP-2930 access list. Defaults to []. |
Common Mismatch Causes
When the client and server hashes don’t match, check these in order:- Stale nonce. The nonce changed between estimation and validation. Re-fetch with
getTransactionCountimmediately before computing the hash. - Gas estimation drift. Gas values differ between client and server. Use the exact values from your
estimateFeesPerGascall. - Address casing. The
toaddress must be lowercased in the canonical string. The SDK handles this, but custom implementations sometimes miss it. - Calldata casing. Same rule: hex characters in calldata must be lowercase. Mixed-case calldata from some ABIs causes mismatches.
- AccessList serialization.
JSON.stringify([])produces[], but non-empty access lists must serialize identically on both sides. Stick with[]unless your transaction requires access list entries.
When You Need This
MandateWallet computes the intent hash automatically during sendTransaction() and transfer(). You only need computeIntentHash directly if you are building a custom signing flow outside of MandateWallet, for example when using MandateClient.rawValidate() with your own gas estimation and signing logic.
For debugging hash mismatches, see the Intent Hash Mismatch troubleshooting guide.
MandateWallet
High-level wallet that computes intent hashes automatically.
Hash Mismatch Debugging
Step-by-step guide to diagnose and fix hash mismatches.
Concepts: Intent Lifecycle
How intents flow from validation to on-chain confirmation.