Smart Contract
The taurusSwap smart contract is written in PyTeal and compiled to TEAL 8+. This page walks through the contract module by module, explaining each ARC-4 method's purpose, verification logic, and state updates.
Contract Structure
contract/
├── __init__.py # Contract entry point
├── arc4_methods.py # ARC-4 method definitions
├── swap.py # Swap verification logic
├── liquidity.py # Add/remove liquidity
├── fees.py # Fee accounting
├── state.py # State layout helpers
└── utils/
├── math.py # 512-bit math helpers
└── verification.py # Invariant checksswap Method
The simple swap method for trades that don't cross tick boundaries:
@arc4.method
def swap(
token_in_index: arc4.UInt64,
token_out_index: arc4.UInt64,
amount_in: arc4.UInt64,
min_out: arc4.UInt64,
claimed_out: arc4.UInt64,
) -> arc4.UInt64:
"""
Execute a swap without tick crossings.
Args:
token_in_index: Index of input token in reserves array
token_out_index: Index of output token
amount_in: Amount of input token (microunits)
min_out: Minimum acceptable output (slippage protection)
claimed_out: Claimed output amount (computed by SDK)
Returns:
Actual output amount transferred
"""
# 1. Verify ASA transfer for input
# 2. Read old state (sumX, sumXSq)
# 3. Compute new state from trade
# 4. Verify torus invariant
# 5. Check claimed_out >= min_out
# 6. Update state
# 7. Emit inner transaction for outputswap_with_crossings Method
For trades that cross one or more tick boundaries:
@arc4.method
def swap_with_crossings(
token_in_index: arc4.UInt64,
token_out_index: arc4.UInt64,
amount_in: arc4.UInt64,
min_out: arc4.UInt64,
trade_recipe: arc4.DynamicArray[TradeSegment],
) -> arc4.UInt64:
"""
Execute a swap that crosses tick boundaries.
Args:
trade_recipe: Array of segments, each with:
- amount_in: Input for this segment
- amount_out: Output for this segment
- tick_crossed_id: ID of tick being crossed (or 0)
- new_tick_state: New state of tick (INTERIOR/BOUNDARY)
"""
# For each segment:
# 1. Apply segment's input/output to state
# 2. Verify invariant holds
# 3. If crossing claimed:
# - Verify α_int normalized == k normalized
# - Flip tick state
# - Re-consolidate pool state
# 4. Final check: total output >= min_outadd_tick Method
Called by LPs to add a new tick (provide concentrated liquidity):
@arc4.method
def add_tick(
r: arc4.UInt64,
k: arc4.UInt64,
token_amounts: arc4.DynamicArray[arc4.UInt64],
position_owner: arc4.Address,
) -> arc4.UInt64:
"""
Add a new tick and create an LP position.
Args:
r: Sphere radius for this tick
k: Hyperplane offset (defines price range)
token_amounts: Amount of each token to deposit
position_owner: Address to receive LP position
Returns:
Tick ID (used for future removal/fee claims)
"""
# 1. Verify n ASA transfers (one per token)
# 2. Compute new consolidated state (r_int, s_bound)
# 3. Create tick box: tick:{id} = {r, k, INTERIOR, totalShares}
# 4. Create position box: pos:{owner}{id} = {shares, fee_checkpoints}
# 5. Update global state (numTicks++, totalR += r)remove_liquidity Method
@arc4.method
def remove_liquidity(
tick_id: arc4.UInt64,
shares_to_remove: arc4.UInt64,
min_amounts: arc4.DynamicArray[arc4.UInt64],
) -> arc4.DynamicArray[arc4.UInt64]:
"""
Remove liquidity from a tick position.
Returns:
Array of amounts returned (one per token)
"""
# 1. Load position box, verify shares_to_remove <= position.shares
# 2. Compute output per token: shares * reserves / totalShares
# 3. Claim outstanding fees (see fee-accounting)
# 4. Update tick state (totalShares -= shares)
# 5. Emit inner ASA transfersclaim_fees Method
@arc4.method
def claim_fees(
tick_id: arc4.UInt64,
) -> arc4.DynamicArray[arc4.UInt64]:
"""
Claim accrued fees for a position.
Returns:
Array of fee amounts (one per token)
"""
# 1. Load position and tick state
# 2. For each token i:
# claimable[i] = positionR * (fee_growth[i] - checkpoint[i]) / PRECISION
# 3. Update checkpoint: checkpoint[i] = fee_growth[i]
# 4. Emit inner ASA transfersRead-Only Methods
@arc4.method
def get_pool_state() -> PoolState:
"""Return global pool state (no state changes)."""
@arc4.method
def get_tick_state(tick_id: arc4.UInt64) -> TickState:
"""Return state of a specific tick."""
@arc4.method
def get_position(owner: arc4.Address, tick_id: arc4.UInt64) -> Position:
"""Return LP position for owner in tick."""Verification Flow
Every state-changing method follows this pattern:
- Preconditions — Check sender, check ASA transfers attached
- Read — Load old state from global/box storage
- Compute — Compute new state from proposed changes
- Verify — Check invariant holds within tolerance
- Update — Write new state to storage
- Emit — Inner transactions for payouts
If any step fails, the entire transaction group reverts. This ensures the invariant is never violated.
Source: The full contract is at contract/pool_app.pyin the repo. See the PyTeal source for exact line numbers.