Protocol Architecture

taurusSwap follows a compute-off-chain, verify-on-chain pattern. This is essential for scalability: the heavy computation (solving the torus invariant for trade output) happens in the SDK, while the contract performs O(1) verification.

The Pattern

On-chain trade computation would require solving a quartic equation (Newton's method iteration), which is too expensive for the AVM opcode budget. Instead:

  1. Frontend — User inputs swap parameters (token in, token out, amount)
  2. SDK — Computes the trade output by solving the torus invariant, returns a quote with claimedOut
  3. Transaction Group — User signs ASA transfer (input) + app call (with claimedOut)
  4. Contract — Verifies the torus invariant still holds with the new state, checks claimedOut ≥ minOut, emits inner transaction payout

The key insight: verification is always O(1), regardless of how many tokens or ticks are involved. The contract never solves equations — it only checks that the proposed solution is valid.

Data Flow

┌─────────────┐
│  Frontend   │
│  (React UI) │
└──────┬──────┘
       │ user input
       ▼
┌─────────────────────────┐
│  SDK (compute quote)    │
│  - readPoolState        │
│  - getSwapQuote         │
│  - solve torus invariant│
└──────────┬──────────────┘
           │ quote: { amountOut, priceImpact }
           ▼
┌─────────────────────────┐
│  Transaction Group      │
│  - ASA transfer (in)    │
│  - App call (swap)      │
│  - Signed by user       │
└──────────┬──────────────┘
           │ atomic group
           ▼
┌─────────────────────────┐
│  Contract (verify)      │
│  - read old state       │
│  - compute new sumX,    │
│    sumXSq from trade    │
│  - evaluate invariant   │
│  - check tolerance      │
│  - inner tx payout      │
└─────────────────────────┘

Smart Contract Methods

The contract exposes these ARC-4 methods:

MethodDescription
swapSimple swap without tick crossings
swap_with_crossingsSwap that crosses one or more tick boundaries
add_tickAdd a new tick (LP provides liquidity)
remove_liquidityRemove liquidity from a tick position
claim_feesClaim accrued fees from a position
get_pool_stateRead-only: return global state
get_tick_stateRead-only: return tick state by ID

Atomic Composition

Algorand's atomic transaction groups enable safe composition:

  • Add liquidity — n ASA transfers (one per token) + app call, all in one group
  • Swap — ASA transfer (input) + app call + inner ASA transfer (output), all atomic
  • Remove liquidity — App call + inner ASA transfers (output), all atomic

Either all transactions succeed or all fail. There's no intermediate state where the user has transferred input but not received output.

Why Not Compute On-Chain?

Solving the torus invariant for Δx_out given Δx_in requires:

  1. Substituting the trade into the invariant
  2. Expanding to get a quartic equation
  3. Using Newton's method to find the root

Newton's method typically requires 10-20 iterations for convergence. Each iteration involves multiple 512-bit multiplications and a division. On the AVM, this would exceed the opcode budget for a single transaction.

By moving computation off-chain, the contract only needs to:

  • Read 2 state values (sumX, sumXSq)
  • Compute new values from the trade (O(1))
  • Evaluate the invariant (O(1))
  • Check tolerance (O(1))

This fits comfortably within the opcode budget, even for large n.

Note:The opcode budget pooling pattern (multiple app calls in one group sharing a budget) could enable on-chain computation for small n, but it's unnecessary complexity. Off-chain compute is simpler and cheaper.