Attestations
The EIP-712 KYC and fee attestation model that authorizes every AsseteraECS action.
Assetera authorizes each on-chain action by issuing a single-use, signed approval: an EIP-712 attestation. Every state-changing call on AsseteraECS must carry one, and it authorizes exactly one action. This keeps personal data and business rules off chain: the contract only checks a signature from a trusted operator role. See Compliance gating for the wider model.
The EIP-712 domain name
The domain separator every attestation is signed under uses the name "AsseteraExchange", not
AsseteraECS. This is deliberate and is not a typo.
EIP712Domain(name: "AsseteraExchange", version: "1", chainId, verifyingContract)The venue was renamed to AsseteraECS, but the domain name is written into the deployed proxies' ERC-7201
namespaced storage by the initializer, which runs exactly once at deploy time. It cannot be changed by an
upgrade, and changing it would in any case change the domain separator and invalidate every attestation
already signed. So for the current deployments the domain name stays "AsseteraExchange". Hardcode that
literal when you build the typed data, or read it from eip712Domain() on the contract.
Signing under "AsseteraECS" produces a different domain separator, and the contract will reject the
attestation as an invalid signature. This is the one place the old name survives on purpose.
KYC attestation
Each KYC-gated call takes a KycAttestation in calldata (two, for two-party settlement). It is
not stored on chain: it is verified, its nonce is burned, and a KycConsumed event records that
it was consumed. It is signed by the operator key holding KYC_OPERATOR_ROLE.
Key fields:
| Field | Purpose |
|---|---|
account | The user the attestation is for; must equal _msgSender(). |
action | Which action it authorizes (Place, Fill, Settle, MakeOffer, ReplaceOffer, AcceptOffer, CancelOffer, SettleOffer, …). |
orderId | The order/offer it binds to (0 for Place / MakeOffer, which have no id yet). |
nonce | Single-use; a consumed nonce cannot be replayed (usedNonce(account, nonce)). |
deadline | Time-bound; expires, and cannot exceed the contract's MAX_KYC_TTL. |
paramsHash | Binds the attestation to the exact call parameters. |
signature | The KYC operator's EIP-712 signature over the above. |
Because each attestation is bound to one account, one action, one orderId, one nonce, and a
short deadline, it cannot be reused, retargeted at a different action, or replayed. The action set is
deliberately granular: for example a CancelOffer attestation can never be replayed as a Cancel.
Fee attestation
Fees are a separate concern from compliance, so they live in their own FeeAttestation, signed by a
distinct FEE_OPERATOR_ROLE. It mirrors the KYC pattern: single-use nonce (its own namespace), deadline
bound by MAX_FEE_TTL, a paramsHash, and the fee terms makerFeeBps / takerFeeBps / feeCollector.
Only the fee-setting actions (placeOrder, placeOrderWithPermit, makeOffer) take both
a KYC and a fee attestation. The two are bound together: same account, same paramsHash, same
action, and both are verified before either nonce is burned. Downstream actions (fillOrder,
cancelOrder, settlement) carry only a KYC attestation and read the fee terms already snapshotted
onto the order or offer. The contract still re-checks the fee cap and the collector allowlist on
chain as defence in depth.
Both attestations are verified, and both nonces burned, before the order or offer is created. The fee terms are then snapshotted on chain, so every later action on that order or offer needs only a KYC attestation. The contract re-checks the fee cap and the collector allowlist on chain either way.
How attestations are produced
A user never signs an attestation themselves. They request an action through the Assetera app; Assetera decides whether it is allowed; and Assetera's attestation authority (an operator key Assetera controls) issues the matching single-use EIP-712 signature. The (gasless, ERC-2771-relayed) call then carries that attestation on chain.
Because approval is gated by Assetera, a frozen or non-compliant user is stopped simply by Assetera declining to issue an attestation: no on-chain block list is needed. See the Assetera app for the user-facing side and Compliance gating for the wider model. For what the contract does once an attestation is accepted, see the Order lifecycle and Offer lifecycle.