Assetera Docs
Smart contracts

Attestations

The EIP-712 KYC and fee attestation model that authorizes every AsseteraExchange action.

Assetera authorizes each on-chain action by issuing a single-use, signed approval: an EIP-712 attestation. Every state-changing call on AsseteraExchange 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.

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:

FieldPurpose
accountThe user the attestation is for; must equal _msgSender().
actionWhich action it authorizes (Place, Fill, Settle, MakeOffer, ReplaceOffer, AcceptOffer, CancelOffer, SettleOffer, …).
orderIdThe order/offer it binds to (0 for Place / MakeOffer, which have no id yet).
nonceSingle-use; a consumed nonce cannot be replayed (usedNonce(account, nonce)).
deadlineTime-bound; expires, and cannot exceed the contract's MAX_KYC_TTL.
paramsHashBinds the attestation to the exact call parameters.
signatureThe 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 are being moved out of the KYC attestation into 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.

Roadmap: fee decoupling is not yet shipped and is off-chain-breaking: it changes the calldata of placeOrder / makeOffer and both EIP-712 typehashes, so backend signing and the event schema must move in lockstep. On the current testnet contract (v3.1.0) the fee fields (makerFeeBps, takerFeeBps, feeCollector) still live inside the KycAttestation and are signed by the KYC operator. Treat the separate fee attestation as the production target, not the current testnet behaviour.

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.

On this page