Skip to main content

Pair Contract Overview

Deployment Address: AgoraStableSwap is deployed at [EXTERNAL LINK NEEDED: Deployment addresses] on all available chains. It is a proxy‐based upgradeable contract, so the address remains constant while logic can be upgraded. For other addresses in the Agora Stable Swap ecosystem, see [EXTERNAL LINK NEEDED: ecosystem addresses].

Access‑Control Roles

Role constantCapabilities
ACCESS_CONTROL_MANAGER_ROLEGrants/revokes any other role
WHITELISTER_ROLEAdds or removes APPROVED_SWAPPER
APPROVED_SWAPPERAllowed to execute swaps through swap, swapTokensForExactTokens, swapExactTokensForTokens
FEE_SETTER_ROLEAdjusts per‑asset purchase fees
TOKEN_REMOVER_ROLERemoves excess tokens & collected fees
PAUSER_ROLEPauses / unpauses swaps
PRICE_SETTER_ROLEPushes oracle price updates

Events

Swap

event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);

Emitted at the end of every successful swap call. Tracks exact in/out amounts (including fees).

Sync

event Sync(uint256 reserve0, uint256 reserve1);

Emitted whenever on‑chain reserves are brought in‑sync with the contract's internal state.

SwapFees

event SwapFees(uint256 token0FeesAccumulated, uint256 token1FeesAccumulated);

Logs the incremental fee amounts captured during a swap.

ConfigureOraclePrice

event ConfigureOraclePrice(uint256 basePrice, int256 annualizedInterestRate);

Fired by configureOraclePrice whenever the on‑chain oracle price curve is updated.

SetOraclePriceBounds

event SetOraclePriceBounds(
uint256 minBasePrice,
uint256 maxBasePrice,
int256 minAnnualizedInterestRate,
int256 maxAnnualizedInterestRate
);

Signals an update to the guardrails enforced on future oracle‑price changes.

SetTokenPurchaseFees

event SetTokenPurchaseFees(uint256 token0PurchaseFee, uint256 token1PurchaseFee);

Emitted when live purchase fees are changed via setTokenPurchaseFees.

SetFeeBounds

event SetFeeBounds(
uint256 minToken0PurchaseFee,
uint256 maxToken0PurchaseFee,
uint256 minToken1PurchaseFee,
uint256 maxToken1PurchaseFee
);

Defines the outer limits within which future purchase‑fee updates must fall.

SetApprovedSwapper

event SetApprovedSwapper(address indexed approvedSwapper, bool isApproved);

Logged when an address is granted or revoked permission to call the low‑level swap.

SetTokenReceiver

event SetTokenReceiver(address indexed tokenReceiver)

Fired by setTokenReceiver when the treasury destination for non‑fee token withdrawals is updated.

SetFeeReceiver

event SetFeeReceiver(address indexed feeReceiver);

Fired by setFeeReceiver when the destination for fee withdrawals is updated.

RemoveTokens

event RemoveTokens(address indexed tokenAddress, uint256 amount)

Emitted by both removeTokens and collectFees.

SetPaused

event SetPaused(bool isPaused);

Global circuit‑breaker toggle, emitted by setPaused.


Read-Only Functions

FunctionReturnsNotes
name()Pair name string ("TOKEN0/TOKEN1‑x.y.z")Versioned human label
isPaused()boolSwap availability
token0() / token1()addressImmutable after init
reserve0() / reserve1()uint256Excludes un‑claimed fees
token0PurchaseFee() / token1PurchaseFee()uint256 (18 dec)Current purchase fee
priceLastUpdated()uint256 (timestamp)
perSecondInterestRate()int256 (18 dec)Signed APR ÷ 365 days
basePrice()uint256 (18 dec)Spot price at priceLastUpdated
token0FeesAccumulated() / token1FeesAccumulated()uint256Un‑collected fees
minToken*PurchaseFee() / maxToken*PurchaseFee()boundsConfig limits
tokenReceiverAddress() / feeReceiverAddress()addressTreasury destinations
minBasePrice() / maxBasePrice()uint256Oracle price guardrails
minAnnualizedInterestRate() / maxAnnualizedInterestRate()int256Oracle APR guardrails
token0Decimals() / token1Decimals()uint8Cached for gas
getPrice()Current price (18 dec)Overloaded version also accepts timestamp
getPriceNormalized()Price scaled so both tokens appear at 18 dec precision
version(){major,minor,patch}Contract logic version

getAmountsOut

function getAmountsOut(
uint256 amountIn,
address[] calldata path
) external view returns (uint256[] memory amounts);

Determines how many output tokens a router‑style swap would return for a given amountIn.

  • Path rules – Must be length 2 and equal to [token0, token1] or [token1, token0]; otherwise reverts InvalidPath / InvalidPathLength.
  • Pricing – Uses the live oracle price getPrice() and the current purchase‑fee parameters for the outgoing token.
  • Liquidity check – Reverts InsufficientLiquidity() if reserves can't satisfy the quote.
  • Return valueamounts[0] == amountIn, amounts[1] == deterministic quote (fees already deducted).

This is a pure view helper—calling it does not move funds or mutate state. This function is used by swapExactTokensForTokens

getAmountsIn

function getAmountsIn(
uint256 amountOut,
address[] calldata path
) external view returns (uint256[] memory amounts);

Inverse of getAmountsOut: calculates the minimum tokens required to receive a specified amountOut.

  • Path rules – Same as above; reverts on invalid path length or composition.
  • Pricing – Considers current oracle price plus purchase fee for the incoming token.
  • Reserve guard – Reverts InsufficientLiquidity() if amountOut exceeds current reserves of the outgoing asset.
  • Return valueamounts[0] == required amountIn, amounts[1] == amountOut. This function is used by swapTokensForExactTokens

State-Changing Functions

Admin / Config

SignatureRoleEffect
setTokenReceiver(address)ACCESS_CONTROL_MANAGER_ROLERedirects excess token withdrawals
setFeeReceiver(address)ACCESS_CONTROL_MANAGER_ROLERedirects fee outflows
setApprovedSwappers(address[] addrs, bool flag)WHITELISTER_ROLEBatch grant / revoke APPROVED_SWAPPER
setFeeBounds(uint256 min0,uint256 max0,uint256 min1,uint256 max1)ACCESS_CONTROL_MANAGER_ROLEHard caps for future fee changes
setTokenPurchaseFees(uint256 fee0,uint256 fee1)FEE_SETTER_ROLEUpdates live purchase fees
setPaused(bool)PAUSER_ROLEGlobal circuit‑breaker
setOraclePriceBounds(uint256 minPrice,uint256 maxPrice,int256 minAPR,int256 maxAPR)ACCESS_CONTROL_MANAGER_ROLEGuardrails for oracle updates
configureOraclePrice(uint256 basePrice,int256 annualizedInterestRate)PRICE_SETTER_ROLEPushes new price and annualized interest rate

Treasury

removeTokens

function removeTokens(address token, uint256 amount) external;

collectFees

function collectFees(address token, uint256 amount) external;
  • Who / RoleTOKEN_REMOVER_ROLE
  • Purpose – Transfers accrued fees to feeReceiverAddress.
  • EventsRemoveTokens(token, amount) then Sync(...)
  • Reverts – Same conditions as removeTokens, but checked against _FeesAccumulated.

Swapping APIs

swapExactTokensForTokens

function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);

High‑level "exact‑in" swap helper (router style).

swapTokensForExactTokens

function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);

High‑level "exact‑out" variant.

swap

function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;

Low‑level primitive that can perform flash‑swaps if data is non‑empty.


Errors

ErrorTrigger
InvalidTokenAddress()Token not in pair for collectFees/removeTokens
InvalidPath() / InvalidPathLength()Path must be [token0,token1] or reverse
InvalidSwapAmounts()Both amount0Out and amount1Out non‑zero or zero
Expired()Deadline passed in router helpers
InsufficientLiquidity()Reserves too low
InvalidToken0PurchaseFee() / InvalidToken1PurchaseFee()Fee outside configured bounds
ExcessiveInputAmount()amountIn exceeds caller‑supplied max
InsufficientOutputAmount()Quoted out < amountOutMin
InsufficientInputAmount()Fewer tokens in than required by pricing
PairIsPaused()Swaps disabled
BasePriceOutOfBounds() / AnnualizedInterestRateOutOfBounds()Oracle update outside guardrails
MinBasePriceGreaterThanMaxBasePrice()Invalid bounds
MinAnnualizedInterestRateGreaterThanMax()
MinToken0PurchaseFeeGreaterThanMax() / MinToken1PurchaseFeeGreaterThanMax()Fee bounds inverted
InsufficientTokens()Treasury withdrawal exceeds balance
IncorrectDecimals()Init decimals mismatch with token contracts

Interface

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

library AgoraStableSwapPair {
struct Version {
uint256 major;
uint256 minor;
uint256 patch;
}
}

interface IAgoraStableSwapPair {
struct InitializeParams {
address token0;
uint8 token0Decimals;
address token1;
uint8 token1Decimals;
uint256 minToken0PurchaseFee;
uint256 maxToken0PurchaseFee;
uint256 minToken1PurchaseFee;
uint256 maxToken1PurchaseFee;
uint256 token0PurchaseFee;
uint256 token1PurchaseFee;
address initialAdminAddress;
address initialWhitelister;
address initialFeeSetter;
address initialTokenRemover;
address initialPauser;
address initialPriceSetter;
address initialTokenReceiver;
address initialFeeReceiver;
uint256 minBasePrice;
uint256 maxBasePrice;
int256 minAnnualizedInterestRate;
int256 maxAnnualizedInterestRate;
uint256 basePrice;
int256 annualizedInterestRate;
}

error AddressIsNotRole(string role);
error AnnualizedInterestRateOutOfBounds();
error BasePriceOutOfBounds();
error CannotRemoveLastManager();
error ExcessiveInputAmount();
error Expired();
error IncorrectDecimals();
error InsufficientInputAmount();
error InsufficientLiquidity();
error InsufficientOutputAmount();
error InsufficientTokens();
error InvalidInitialization();
error InvalidPath();
error InvalidPathLength();
error InvalidSwapAmounts();
error InvalidToken0PurchaseFee();
error InvalidToken1PurchaseFee();
error InvalidTokenAddress();
error MinAnnualizedInterestRateGreaterThanMax();
error MinBasePriceGreaterThanMaxBasePrice();
error MinToken0PurchaseFeeGreaterThanMax();
error MinToken1PurchaseFeeGreaterThanMax();
error NotInitializing();
error PairIsPaused();
error ReentrancyGuardReentrantCall();
error RoleNameTooLong();
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
error SafeERC20FailedOperation(address token);

event ConfigureOraclePrice(uint256 basePrice, int256 annualizedInterestRate);
event Initialized(uint64 version);
event RemoveTokens(address indexed tokenAddress, uint256 amount);
event RoleAssigned(string indexed role, address indexed address_);
event RoleRevoked(string indexed role, address indexed address_);
event SetApprovedSwapper(address indexed approvedSwapper, bool isApproved);
event SetFeeBounds(
uint256 minToken0PurchaseFee,
uint256 maxToken0PurchaseFee,
uint256 minToken1PurchaseFee,
uint256 maxToken1PurchaseFee
);
event SetFeeReceiver(address indexed feeReceiver);
event SetOraclePriceBounds(
uint256 minBasePrice,
uint256 maxBasePrice,
int256 minAnnualizedInterestRate,
int256 maxAnnualizedInterestRate
);
event SetPaused(bool isPaused);
event SetTokenPurchaseFees(uint256 token0PurchaseFee, uint256 token1PurchaseFee);
event SetTokenReceiver(address indexed tokenReceiver);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event SwapFees(uint256 token0FeesAccumulated, uint256 token1FeesAccumulated);
event Sync(uint256 reserve0, uint256 reserve1);

function ACCESS_CONTROL_MANAGER_ROLE() external view returns (string memory);

function AGORA_ACCESS_CONTROL_STORAGE_SLOT() external view returns (bytes32);

function AGORA_STABLE_SWAP_STORAGE_SLOT() external view returns (bytes32);

function APPROVED_SWAPPER() external view returns (string memory);

function FEE_PRECISION() external view returns (uint256);

function FEE_SETTER_ROLE() external view returns (string memory);

function PAUSER_ROLE() external view returns (string memory);

function PRICE_PRECISION() external view returns (uint256);

function PRICE_SETTER_ROLE() external view returns (string memory);

function TOKEN_REMOVER_ROLE() external view returns (string memory);

function WHITELISTER_ROLE() external view returns (string memory);

function assignRole(string memory _role, address _newAddress, bool _addRole) external;

function basePrice() external view returns (uint256);

function calculatePrice(
uint256 _priceLastUpdated,
uint256 _timestamp,
int256 _perSecondInterestRate,
uint256 _basePrice
) external pure returns (uint256 _price);

function collectFees(address _tokenAddress, uint256 _amount) external;

function configureOraclePrice(uint256 _basePrice, int256 _annualizedInterestRate) external;

function feeReceiverAddress() external view returns (address);

function getAllRoles() external view returns (string[] memory _roles);

function getAmount0In(
uint256 _amount1Out,
uint256 _token0OverToken1Price,
uint256 _token1PurchaseFee
) external pure returns (uint256 _amount0In, uint256 _token1PurchaseFeeAmount);

function getAmount0Out(
uint256 _amount1In,
uint256 _token0OverToken1Price,
uint256 _token0PurchaseFee
) external pure returns (uint256 _amount0Out, uint256 _token0PurchaseFeeAmount);

function getAmount1In(
uint256 _amount0Out,
uint256 _token0OverToken1Price,
uint256 _token0PurchaseFee
) external pure returns (uint256 _amount1In, uint256 _token0FeeAmount);

function getAmount1Out(
uint256 _amount0In,
uint256 _token0OverToken1Price,
uint256 _token1PurchaseFee
) external pure returns (uint256 _amount1Out, uint256 _token1PurchaseFeeAmount);

function getAmountsIn(uint256 _amountOut, address[] memory _path) external view returns (uint256[] memory _amounts);

function getAmountsOut(uint256 _amountIn, address[] memory _path) external view returns (uint256[] memory _amounts);

function getPrice() external view returns (uint256 _currentPrice);

function getPrice(uint256 _timestamp) external view returns (uint256 _price);

function getPriceNormalized() external view returns (uint256 _normalizedPrice);

function getRoleMembers(string memory _role) external view returns (address[] memory _members);

function hasRole(string memory _role, address _address) external view returns (bool);

function implementationAddress() external view returns (address);

function initialize(InitializeParams memory _params) external;

function isPaused() external view returns (bool);

function maxAnnualizedInterestRate() external view returns (int256);

function maxBasePrice() external view returns (uint256);

function maxToken0PurchaseFee() external view returns (uint256);

function maxToken1PurchaseFee() external view returns (uint256);

function minAnnualizedInterestRate() external view returns (int256);

function minBasePrice() external view returns (uint256);

function minToken0PurchaseFee() external view returns (uint256);

function minToken1PurchaseFee() external view returns (uint256);

function name() external view returns (string memory);

function perSecondInterestRate() external view returns (int256);

function priceLastUpdated() external view returns (uint256);

function proxyAdminAddress() external view returns (address);

function removeTokens(address _tokenAddress, uint256 _amount) external;

function requireValidPath(address[] memory _path, address _token0, address _token1) external pure;

function reserve0() external view returns (uint256);

function reserve1() external view returns (uint256);

function setApprovedSwappers(address[] memory _approvedSwappers, bool _setApproved) external;

function setFeeBounds(
uint256 _minToken0PurchaseFee,
uint256 _maxToken0PurchaseFee,
uint256 _minToken1PurchaseFee,
uint256 _maxToken1PurchaseFee
) external;

function setFeeReceiver(address _feeReceiver) external;

function setOraclePriceBounds(
uint256 _minBasePrice,
uint256 _maxBasePrice,
int256 _minAnnualizedInterestRate,
int256 _maxAnnualizedInterestRate
) external;

function setPaused(bool _setPaused) external;

function setTokenPurchaseFees(uint256 _token0PurchaseFee, uint256 _token1PurchaseFee) external;

function setTokenReceiver(address _tokenReceiver) external;

function swap(uint256 _amount0Out, uint256 _amount1Out, address _to, bytes memory _data) external;

function swapExactTokensForTokens(
uint256 _amountIn,
uint256 _amountOutMin,
address[] memory _path,
address _to,
uint256 _deadline
) external returns (uint256[] memory _amounts);

function swapTokensForExactTokens(
uint256 _amountOut,
uint256 _amountInMax,
address[] memory _path,
address _to,
uint256 _deadline
) external returns (uint256[] memory _amounts);

function sync() external;

function token0() external view returns (address);

function token0Decimals() external view returns (uint8);

function token0FeesAccumulated() external view returns (uint256);

function token0PurchaseFee() external view returns (uint256);

function token1() external view returns (address);

function token1Decimals() external view returns (uint8);

function token1FeesAccumulated() external view returns (uint256);

function token1PurchaseFee() external view returns (uint256);

function tokenReceiverAddress() external view returns (address);

function version() external pure returns (AgoraStableSwapPair.Version memory _version);
}

ABI

The ABI of the AgorastableSwapPair is available here