AsseteraAssetera Docs
Smart contracts

Offer lifecycle

The regulator-mandated targeted offer and counter-offer negotiation flow in AsseteraECS.

An offer is a bilateral, targeted negotiation: a maker proposes specific terms to a specific taker, who may accept, counter, or walk away. Unlike an order (open to any taker), an offer is aimed at one counterparty and supports back-and-forth counter-proposals before either side commits funds.

This targeted offer / counter-offer flow is a regulatory requirement, not an optional convenience. As a MiFID venue, Assetera must support directed, negotiable quotes between a named maker and a named taker. It is a first-class part of AsseteraECS, not sugar over the order book.

State machine

The on-chain OfferStatus enum is: None, Open, Countered, Accepted, Settled, Cancelled, ForceCancelled, Expired. Accepted retains its numeric position for storage and ABI compatibility but is never persisted: acceptance settles atomically and writes Settled. Each offer tracks proposedBy, the party whose terms are currently on the table and whose tokens are escrowed for the current round.

Making an offer

makeOffer(taker, makerToken, makerAmount, takerToken, takerAmount, expireTs, att) opens an offer targeted at taker, requiring a KYC attestation for the MakeOffer action. It snapshots the fee terms onto the offer (fixed at makeOffer, never renegotiated) and emits OfferMade. The maker cannot target themselves. It returns the new offer id.

Countering

replaceOffer(offerId, newMakerAmount, newTakerAmount, expireTs, att) is the negotiation step: either party (maker or taker) can put fresh terms on the table while the offer is Open or Countered, requiring a KYC attestation for the ReplaceOffer action. It flips proposedBy to the caller (the new proposer's side becomes the escrowed side) and emits OfferReplaced. Fee terms do not change across counters; they stay fixed from makeOffer. Counters can go back and forth any number of times.

Accepting

acceptOffer(offerId, att) is called by the non-proposing party (you can't accept your own proposal), requiring a KYC attestation for the AcceptOffer action. It brings in the accepting side, settles both legs atomically, writes Settled, and emits OfferAccepted followed by OfferSettled in the same transaction.

Settling

There is no public settleOffer step in the current ABI. Settlement happens inside acceptOffer, so there is no accepted-but-unsettled period for an operator or client to advance. Both fees are denominated in the configured settlement currency, and the asset leg moves gross. Use the deployment ABI for the exact OfferSettled event fields.

Cancelling and expiry

Either party can cancel while the offer is Open or Countered via cancelOffer(offerId, att) (KYC-gated on the CancelOffer action), which returns the currently-escrowed proposer's side and emits OfferCancelled. Offers past their expireTs are swept by the permissionless, batched sweepExpiredOffers(ids[]), which returns escrow to the current proposedBy and emits one OfferExpired per swept id.

The admin escape hatch cancelOfferForUser(offerId, makerRecipient, takerRecipient) works while the offer is Open or Countered, returns the current proposer's escrow to the applicable recipient, and emits OfferForceCancelled.

AcceptOffer, ReplaceOffer, and CancelOffer attestations are action- and offer-bound. A public SettleOffer function is not present; that enum value is retained only for ordinal compatibility.

For the full event field lists, see Events. For how attestations are produced, see Attestations.

On this page