onus. documentation

How to write, lock, prove and lapse a conditional payment on Arc. Sections 01–05 get you to a first release; the rest is reference.

01Overview

onus. is conditional settlement on Arc. An onus is a contract instance holding stablecoins (USDC, EURC or JPYSC) that releases to a payee when a condition is proven by a named witness, or returns to the payer when a lapse date passes without proof.

There is no admin key, no pause and no discretionary release. onus. the company operates a registry and an SDK; it cannot move funds in any onus.

02Vocabulary

termmeaning
onusOne conditional payment: payer, payee, amount, currency, condition, witness, lapse.
conditionA predicate over Arc state (C1 delivery · C2 oracle · C3 result · C4 time).
witnessThe source that supplies the state: attester, feed, checker, clock, resolver.
lapseTimestamp after which funds return to the payer if not released.
trancheA portion of the amount tied to its own condition.
checkerA contract returning true/false on (spec, result).
resolverThe witness that decides a dispute in a C4 onus.

03Quickstart

import { onus } from "@onus/sdk";

const o = await onus.write({
  payee: "0x9f2a…c41e", amount: "12500", currency: "USDC",
  condition: { kind: "delivery", attester: "0x7d…a1", schema: "delivery/v1", ref: "PO-4127" },
  lapse: "30d"
});                        // payer signs
await onus.accept(o.id);   // payee countersigns
await onus.lock(o.id);     // payer funds
// … carrier attests on Arc …
await onus.prove(o.id);    // anyone; verifies + releases

04Install

npm install @onus/sdk

Targets Arc mainnet by default; { network: "arc-testnet" } for testnet. Gas is paid in USDC; the SDK estimates it per call.

05Write your first onus

  1. Pick a witness from the registry (§20) or an address you both trust.
  2. onus.write() with payee, amount, currency, condition, lapse. You sign.
  3. Send the id to the payee; they accept(). Terms are frozen at this point.
  4. lock() transfers funds in.
  5. When the witness has supplied the state, anyone calls prove(); the contract verifies and releases.
An onus that is written but not locked holds nothing and expires after 7 days.

06Onuses

Each onus is a minimal proxy contract on Arc. Immutable after accept(): payee, amount, currency, condition, witness, lapse, tranches, payout currency and band. The payer can cancel before the payee accepts; after acceptance only the condition or the lapse can end it.

07Conditions

kindreadsreleases when
C1 deliveryEAS attestationattester signs schema against ref
C2 oraclefeed valuecomparison holds (optionally sustained)
C3 resultchecker(spec, result)checker returns true
C4 timeblock time + dispute flagT reached and no dispute

Combine with and, or, then. Every branch must terminate in release or lapse (§16).

08Witnesses

Named by address at write time; frozen at accept. The contract only accepts state from that address (attester, feed, checker, resolver) or from the chain (clock). A witness cannot be swapped after acceptance, even by both parties — write a new onus instead.

09Lapse

Every onus has a lapse timestamp. After it, lapse() is callable by anyone and returns funds to the payer. A pending dispute (C4) suspends lapse until the resolver decides. Maximum lapse is 365 days.

10Tranches

tranches: [
  { amount: "5000", condition: { kind: "result", spec: "0xaaa…", checker: "0xC…" } },
  { amount: "7500", condition: { kind: "result", spec: "0xbbb…", checker: "0xC…" } }
]

Each tranche releases independently. Unreleased tranches lapse together at the onus lapse date.

11Disputes & resolvers

Only C4 conditions carry a dispute path. The named disputant calls dispute() before lapse; the onus freezes; the named resolver calls resolve(release | return). Resolvers are registry witnesses with records. C1–C3 have no dispute path by design.

12Currencies & StableFX

Lock in USDC, EURC or JPYSC. Optionally set payout: { currency, band }; at release the onus converts via StableFX on Arc if the rate is inside the band, otherwise pays in the locked currency. An onus never fails to pay on a valid release.

13Nano-onuses

Amounts down to 0.000001 USDC via Arc nanopayments. For chains of tiny onuses the SDK batches write+accept+lock into one call per step and prove into one call per batch of results.

14Architecture

payer ── write/lock ──▶ OnusFactory ──▶ Onus (proxy)  ◀── accept ── payee
                                          │ reads
     attester (EAS) · feed · checker · clock · resolver   = witnesses
                                          │ release / lapse
                                        payee / payer  (StableFX hop optional)

No off-chain component is in the settlement path. The registry and SDK are conveniences.

15Onus contract

functioncallerdoes
accept()payeefreezes terms
lock()payerpulls funds (after approval)
cancel()payeronly before accept
prove(bytes)anyoneverifies condition against witness; releases
lapse()anyoneafter lapse timestamp; returns funds
dispute() / resolve()disputant / resolverC4 only

No owner, no upgrade, no pause.

16Condition language

cond  := atom | cond "and" cond | cond "or" cond | cond "then" cond
atom  := attest(by, schema, ref)
       | feed(addr).field cmp value [for window]
       | check(addr, spec, result)
       | time(T) [unless dispute(by)]
cmp   := >= | <= | == | > | <

Compiled at write time into a small bytecode the onus contract evaluates. Rejected if any branch fails to terminate in release or lapse.

17Attestations (EAS)

C1 uses the Ethereum Attestation Service deployment on Arc. Core schema delivery/v1: ref (string), deliveredAt (uint64), by (address). Custom schemas may be named; the onus stores the schema UID.

18Feeds

C2 reads any contract exposing latest() → (value, timestamp). The onus stores the feed address and required freshness. onus. recommends naming a second feed as a bound: feed(A) within 1% of feed(B).

19Checker interface

interface IChecker {
  function check(bytes32 spec, bytes calldata result) external view returns (bool);
}

Must be view/pure so release is deterministic. Checkers needing off-chain computation post a signed verdict via an attestation instead (pattern in §31).

20Witness registry

Open registry on Arc: name, kind, schema/interface, and a live record (served, released, lapsed, disputed). Listing is permissionless; onus. endorses nothing. The SDK shows the record at write time.

21Fees

  • Write / accept / lock / prove / lapse: Arc gas in USDC, each well under a cent.
  • Protocol fee: a small flat fee at release, none at lapse.
  • StableFX hop: Circle's rate; no onus. markup.

22Security model

if compromisedcancannot
onus. servers / SDKshow wrong datamove funds — no key exists
a witnessrelease or withhold on its onusestouch other witnesses' onuses; escape the registry record
payer keywrite/lock/cancel-before-acceptrelease or reclaim a locked onus early
payee keyaccept; receiverelease

23onus.write()

onus.write(o: {
  payee: Address; amount: string; currency: "USDC"|"EURC"|"JPYSC";
  condition: Condition; witness?: Address;      // inferred from condition where unique
  lapse: string;                                // "30d", ISO date
  tranches?: Tranche[];
  payout?: { currency: string; band?: [number, number] };
}): Promise<{ id: string; address: Address }>

24onus.lock() / accept()

await onus.accept(id)   // payee
await onus.lock(id)     // payer; handles ERC-20 approval
await onus.cancel(id)   // payer; before accept only

25onus.prove() / lapse()

await onus.prove(id, proof?)   // proof optional: attestation uid, result bytes
await onus.lapse(id)           // after lapse timestamp
await onus.status(id)          // draft | accepted | locked | released | lapsed | disputed

26Contract interface

interface IOnus {
  function terms() external view returns (Terms memory);
  function status() external view returns (uint8);
  function accept() external;
  function lock() external;
  function cancel() external;
  function prove(bytes calldata proof) external;
  function lapse() external;
  function dispute() external;
  function resolve(bool release) external;
}

27Events

Written(id, payer, payee, amount, currency, lapse)
Accepted(id)   Locked(id, amount)
Released(id, payee, amount, currency, tranche)
Lapsed(id, payer, amount)
Disputed(id, by)   Resolved(id, release)

28Errors

codemeaning
E_NOT_ACCEPTEDlock before payee accepted
E_TERMS_FROZENcancel after accept
E_WITNESSproof not from the named witness
E_CONDITIONproof supplied but condition not satisfied
E_NOT_LAPSEDlapse called before timestamp
E_DISPUTEDonus frozen pending resolver
E_BANDpayout currency outside band; paid in locked currency instead (not an error to the payee)

29Guide: pay a supplier on delivery

  1. Agree a carrier or receiving party as attester; check their registry record.
  2. Write a C1 onus with the PO number as ref and a lapse after the latest acceptable delivery date.
  3. Supplier accepts; you lock.
  4. On delivery the attester signs; anyone calls prove(); supplier is paid the same block.

30Guide: pay an agent per result

  1. Hash the task spec; pick or deploy a checker (§31).
  2. Write a C3 onus with a short lapse (hours).
  3. The working agent accepts and submits; prove(result) runs the checker.
  4. For long tasks, one nano-onus per step.

31Guide: write a checker

Implement IChecker.check() as a view. For off-chain verification (running tests, calling a model), have the verifier post an EAS attestation verdict/v1 (spec, resultHash, pass) and make the checker read it. Register the checker so others can name it.

32Safety checklist

  • Read the witness's record before naming it.
  • Name a second feed as a bound on C2.
  • Keep lapse as short as the task allows.
  • Use tranches for anything with milestones.
  • Set a payout band if converting currency.
  • Remember: after accept, nothing can be changed.

33FAQ

Can onus. release funds if a witness disappears?

No. The onus lapses and funds return to the payer.

Can both parties agree to cancel a locked onus?

No. Write the lapse you can live with.

Is this escrow?

Functionally. Legally, onus. is software and holds nothing; the contract holds the funds.

Which chains?

Arc only. Gas in USDC, StableFX and nanopayments are the reason.

Can a person be a witness?

Yes, as an attester or resolver with an address and a record.

34Glossary

attester — signs EAS attestations. band — acceptable FX range at release. checker — result verifier contract. condition — release predicate. lapse — return-to-payer deadline. onus — one conditional payment. resolver — dispute decider. tranche — sub-amount with its own condition. witness — state source.