AsseteraAssetera Docs
Smart contracts

Order lifecycle

The AsseteraECS order state machine (place, fill, cancel and expire), and what each step escrows and attests.

An order is a maker's standing intent to trade one token for another. The maker escrows the token they are selling up front, and takers fill against it directly. Orders are 1-indexed (getOrder(id) reads one; totalOrders() is the high-water mark).

There is no on-chain matching engine: a taker names the order id it wants to execute against. The contract never scans the book for a cross, which is why the transitions below are all explicit calls. The full behavioural spec is FUNCTIONAL_SPEC.md in the public contracts repo.

State machine

The on-chain OrderStatus enum is: None, Open, Filled, Settled, Cancelled, Refunded, ForceCancelled, Expired. Settled and Refunded retain their numeric positions for storage and ABI compatibility, but no current function writes those states. A newly placed order is Open; every reachable terminal transition emits one lifecycle event.

Placing an order

placeOrder(sellToken, sellAmount, buyToken, buyAmount, expireTs, att, feeAtt) escrows the maker's sell leg and any required maker fee. It requires a valid KYC attestation for the Place action and a separate fee attestation. The fee terms and settlement currency are snapshotted onto the order and remain immutable. expireTs of 0 means the order never expires. It emits OrderPlaced and returns the new order id.

placeOrderWithPermit(...) is the same call with an ERC-2612 permit attempted first (best-effort, swallowed on failure) so the maker can approve and place in one transaction.

Filling an order

fillOrder(id, fillSellAmount, att) lets a taker trade against an open order, requiring a KYC attestation for the Fill action. Fills can be partial or full:

  • Partial (order still has remaining quantity afterwards) emits OrderPartiallyFilled and the order stays Open.
  • Full (remaining quantity reaches zero) emits OrderFilled and the order becomes Filled.

Both fees are denominated in the market's settlement currency. The currency payer supplies the notional plus their fee, the currency receiver receives the notional less their fee, and the asset leg moves gross. The buy-side amount is ceiling-divided so the maker does not lose to rounding.

Operator settle and refund functions are not part of the current contract ABI. Orders execute through fillOrder; self-cancel, expiry sweep, and the admin force-cancel path handle remaining escrow.

Cancelling

A maker cancels their own open order with cancelOrder(id) and reclaims the escrowed remaining quantity, emitting OrderCancelled. The call takes no attestation: a user must always be able to cancel their own open order and reclaim escrow, so cancellation is never gated on a compliance signature.

Expiry and sweeping

An order past its expireTs is dead but its escrow is still locked until swept. sweepExpired(ids[]) is permissionless and batched (≤100 ids). It refunds each expired order's remaining quantity to the rightful maker (not the caller), silently skipping ineligible ids, and emits one OrderExpired per swept id. Anyone can sweep a user's expired orders on their behalf.

Sweeping is a caller-triggered contract action. Integrators should run or use an operational sweeper if they want expired escrow returned promptly; the contract does not execute calls on its own.

Escape hatches

The admin-gated cancelOrderForUser(id, recipient) escape hatch force-cancels an open order and routes its remaining escrow to the maker or another compliance-directed recipient. It emits OrderForceCancelled.

On this page