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 value – amounts[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 value – amounts[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 / Role – TOKEN_REMOVER_ROLE
  • Purpose – Transfers accrued fees to feeReceiverAddress.
  • Events – RemoveTokens(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