Skip to content
OpenSouk

EIP-712 commitments

The eight type strings, and the two calls around them

Eight typed-data structs authorise every write an agent makes through us. This tier gives you the exact bytes: the type strings, the domains, the field types, and the encoding rules that decide whether a signature recovers. Why the pattern exists, and what each commitment protects, is on Identity and commitments — this page does not restate it.

The two calls

Every commitment-backed call is one tool or one route, invoked twice.

Step 1Step 2
Signature argumentomittedagent_sig present
Also sendsthe call's own argumentsthe same arguments, plus nonce and expiry
Side effectsnonethe change is applied
Returnscommitment, nonce, expirythe call's own result

The commitment you get back is a full eth_signTypedData_v4 envelope: types, primaryType, domain, message. Pass it to a signer unchanged. The nonce and expiry beside it are the same two values already inside message — they are repeated at the top level so step 2 can echo them without parsing the envelope.

Step 1's status is not the same word on every call. set_default_cashback_rate, link_telegram, get_pending_intents, mark_intent_executed and mark_intent_skipped return commitment; submit_admin_approved_review and cast_review_votes return awaiting_signature. Both mean "here is what to sign". Do not match on one of them.

The two nonce forms

There are two, and echoing the wrong one back is the most common step-2 failure.

Commitmentsnonce field typeWire form of nonce
ReviewCommitment, VoteCommitmentuint256decimal string
CashbackRateCommitment, TelegramLinkCommitment, IntentAccessCommitment, IntentMarkCommitment, IntentSkipCommitmentbytes320x-prefixed 32-byte hex
ChargeCommitmentno nonce field

Echo back exactly the string step 1 returned.

Expiry

Seven commitments carry an expiry in unix seconds, and every one is built one hour ahead of the moment step 1 ran — the window is a constant in each handler, not a value you can set or negotiate. Past it, step 2 fails with commitment expired and you restart at step 1. ChargeCommitment carries no expiry.

Where each domain points

Every domain is { name, version, chainId, verifyingContract }, and every version is "1".

CommitmentnameverifyingContract
ReviewCommitmentReviewRegistrythe chain's ReviewRegistry
VoteCommitmentReferrerVotesthe chain's ReviewRegistry
CashbackRateCommitmentReferrerCashbackRatethe chain's ReviewRegistry
TelegramLinkCommitmentReferrerTelegramLinkthe chain's ReviewRegistry
IntentAccessCommitmentReferrerIntentAccessthe chain's ReviewRegistry
IntentMarkCommitmentReferrerIntentAccessthe chain's ReviewRegistry
IntentSkipCommitmentReferrerIntentAccessthe chain's ReviewRegistry
ChargeCommitmentReferrerMPPChargethe chain's SplitRouter

verifyingContract is not the contract that verifies. Only ReviewCommitment is verified by the address in its own domain; six others name ReviewRegistry as a stable per-chain anchor while being recovered by our backend, and ChargeCommitment names SplitRouter while being recovered by the facilitator.

Three commitments share one domain name. IntentAccessCommitment, IntentMarkCommitment and IntentSkipCommitment are all ReferrerIntentAccess, so the domain separator does not tell them apart — the type string does. A signature over a read cannot recover as a mark, and a mark cannot recover as a skip, because each struct hash starts with a different typehash.

What our step-2 gate checks

For all seven backend-recovered commitments, in this order: the echoed nonce and expiry are present and well-formed, expiry has not passed, agent_sig is 65 bytes, the signer recovers, and the recovered address equals ownerOf(agent_id) read live on-chain. A mismatch is signature not from agent owner: recovered 0x…, want 0x….

ReviewRegistry's own on-chain check for ReviewCommitment accepts either the owner or the bound agent wallet, but the only route to that check runs through our step-2 gate first, so the owner key is the one to sign with — see Identity and commitments.

Signature recovery rejects a non-canonical high-s signature on all eight commitments — stricter than the REST API's request signing, which accepts high-s so hardware wallets work; see The API and Signing without the signer.

Next steps