Pair Contract

Deployment Address: AgoraStableSwap is deployed with CREATE3 using a salt derived from token0 + token1, which guarantees the address can be predicted off-chain before the contract exists. The contract is a proxy‐based upgradeable contract, so the address remains constant while logic can be upgraded.

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

1event Swap(
2 address indexed sender,
3 uint256 amount0In,
4 uint256 amount1In,
5 uint256 amount0Out,
6 uint256 amount1Out,
7 address indexed to
8);

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

Sync

1event Sync(uint256 reserve0, uint256 reserve1);

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

SwapFees

1event SwapFees(uint256 token0FeesAccumulated, uint256 token1FeesAccumulated);

Logs the incremental fee amounts captured during a swap.

ConfigureOraclePrice

1event ConfigureOraclePrice(uint256 basePrice, int256 annualizedInterestRate);

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

SetOraclePriceBounds

1event SetOraclePriceBounds(
2 uint256 minBasePrice,
3 uint256 maxBasePrice,
4 int256 minAnnualizedInterestRate,
5 int256 maxAnnualizedInterestRate
6);

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

SetTokenPurchaseFees

1event SetTokenPurchaseFees(uint256 token0PurchaseFee, uint256 token1PurchaseFee);

Emitted when live purchase fees are changed via setTokenPurchaseFees.

SetFeeBounds

1event SetFeeBounds(
2 uint256 minToken0PurchaseFee,
3 uint256 maxToken0PurchaseFee,
4 uint256 minToken1PurchaseFee,
5 uint256 maxToken1PurchaseFee
6);

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

SetApprovedSwapper

1event SetApprovedSwapper(address indexed approvedSwapper, bool isApproved);

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

SetTokenReceiver

1event SetTokenReceiver(address indexed tokenReceiver)

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

SetFeeReceiver

1event SetFeeReceiver(address indexed feeReceiver);

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

RemoveTokens

1event RemoveTokens(address indexed tokenAddress, uint256 amount)

Emitted by both removeTokens and collectFees.

SetPaused

1event 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

1function getAmountsOut(
2 uint256 amountIn,
3 address[] calldata path
4) 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

1function getAmountsIn(
2 uint256 amountOut,
3 address[] calldata path
4) 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

Treasury

removeTokens

1function removeTokens(address token, uint256 amount) external;

collectFees

1function 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

1function swapExactTokensForTokens(
2 uint256 amountIn,
3 uint256 amountOutMin,
4 address[] calldata path,
5 address to,
6 uint256 deadline
7) external returns (uint256[] memory amounts);

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

swapTokensForExactTokens

1function swapTokensForExactTokens(
2 uint256 amountOut,
3 uint256 amountInMax,
4 address[] calldata path,
5 address to,
6 uint256 deadline
7) external returns (uint256[] memory amounts);

High‑level “exact‑out” variant.

swap

1function swap(
2 uint256 amount0Out,
3 uint256 amount1Out,
4 address to,
5 bytes calldata data
6) 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

1// SPDX-License-Identifier: BUSL-1.1
2pragma solidity ^0.8.4;
3
4library AgoraStableSwapPair {
5 struct Version {
6 uint256 major;
7 uint256 minor;
8 uint256 patch;
9 }
10}
11
12interface IAgoraStableSwapPair {
13 struct InitializeParams {
14 address token0;
15 uint8 token0Decimals;
16 address token1;
17 uint8 token1Decimals;
18 uint256 minToken0PurchaseFee;
19 uint256 maxToken0PurchaseFee;
20 uint256 minToken1PurchaseFee;
21 uint256 maxToken1PurchaseFee;
22 uint256 token0PurchaseFee;
23 uint256 token1PurchaseFee;
24 address initialAdminAddress;
25 address initialWhitelister;
26 address initialFeeSetter;
27 address initialTokenRemover;
28 address initialPauser;
29 address initialPriceSetter;
30 address initialTokenReceiver;
31 address initialFeeReceiver;
32 uint256 minBasePrice;
33 uint256 maxBasePrice;
34 int256 minAnnualizedInterestRate;
35 int256 maxAnnualizedInterestRate;
36 uint256 basePrice;
37 int256 annualizedInterestRate;
38 }
39
40 error AddressIsNotRole(string role);
41 error AnnualizedInterestRateOutOfBounds();
42 error BasePriceOutOfBounds();
43 error CannotRemoveLastManager();
44 error ExcessiveInputAmount();
45 error Expired();
46 error IncorrectDecimals();
47 error InsufficientInputAmount();
48 error InsufficientLiquidity();
49 error InsufficientOutputAmount();
50 error InsufficientTokens();
51 error InvalidInitialization();
52 error InvalidPath();
53 error InvalidPathLength();
54 error InvalidSwapAmounts();
55 error InvalidToken0PurchaseFee();
56 error InvalidToken1PurchaseFee();
57 error InvalidTokenAddress();
58 error MinAnnualizedInterestRateGreaterThanMax();
59 error MinBasePriceGreaterThanMaxBasePrice();
60 error MinToken0PurchaseFeeGreaterThanMax();
61 error MinToken1PurchaseFeeGreaterThanMax();
62 error NotInitializing();
63 error PairIsPaused();
64 error ReentrancyGuardReentrantCall();
65 error RoleNameTooLong();
66 error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
67 error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
68 error SafeERC20FailedOperation(address token);
69
70 event ConfigureOraclePrice(uint256 basePrice, int256 annualizedInterestRate);
71 event Initialized(uint64 version);
72 event RemoveTokens(address indexed tokenAddress, uint256 amount);
73 event RoleAssigned(string indexed role, address indexed address_);
74 event RoleRevoked(string indexed role, address indexed address_);
75 event SetApprovedSwapper(address indexed approvedSwapper, bool isApproved);
76 event SetFeeBounds(
77 uint256 minToken0PurchaseFee,
78 uint256 maxToken0PurchaseFee,
79 uint256 minToken1PurchaseFee,
80 uint256 maxToken1PurchaseFee
81 );
82 event SetFeeReceiver(address indexed feeReceiver);
83 event SetOraclePriceBounds(
84 uint256 minBasePrice,
85 uint256 maxBasePrice,
86 int256 minAnnualizedInterestRate,
87 int256 maxAnnualizedInterestRate
88 );
89 event SetPaused(bool isPaused);
90 event SetTokenPurchaseFees(uint256 token0PurchaseFee, uint256 token1PurchaseFee);
91 event SetTokenReceiver(address indexed tokenReceiver);
92 event Swap(
93 address indexed sender,
94 uint256 amount0In,
95 uint256 amount1In,
96 uint256 amount0Out,
97 uint256 amount1Out,
98 address indexed to
99 );
100 event SwapFees(uint256 token0FeesAccumulated, uint256 token1FeesAccumulated);
101 event Sync(uint256 reserve0, uint256 reserve1);
102
103 function ACCESS_CONTROL_MANAGER_ROLE() external view returns (string memory);
104
105 function AGORA_ACCESS_CONTROL_STORAGE_SLOT() external view returns (bytes32);
106
107 function AGORA_STABLE_SWAP_STORAGE_SLOT() external view returns (bytes32);
108
109 function APPROVED_SWAPPER() external view returns (string memory);
110
111 function FEE_PRECISION() external view returns (uint256);
112
113 function FEE_SETTER_ROLE() external view returns (string memory);
114
115 function PAUSER_ROLE() external view returns (string memory);
116
117 function PRICE_PRECISION() external view returns (uint256);
118
119 function PRICE_SETTER_ROLE() external view returns (string memory);
120
121 function TOKEN_REMOVER_ROLE() external view returns (string memory);
122
123 function WHITELISTER_ROLE() external view returns (string memory);
124
125 function assignRole(string memory _role, address _newAddress, bool _addRole) external;
126
127 function basePrice() external view returns (uint256);
128
129 function calculatePrice(
130 uint256 _priceLastUpdated,
131 uint256 _timestamp,
132 int256 _perSecondInterestRate,
133 uint256 _basePrice
134 ) external pure returns (uint256 _price);
135
136 function collectFees(address _tokenAddress, uint256 _amount) external;
137
138 function configureOraclePrice(uint256 _basePrice, int256 _annualizedInterestRate) external;
139
140 function feeReceiverAddress() external view returns (address);
141
142 function getAllRoles() external view returns (string[] memory _roles);
143
144 function getAmount0In(
145 uint256 _amount1Out,
146 uint256 _token0OverToken1Price,
147 uint256 _token1PurchaseFee
148 ) external pure returns (uint256 _amount0In, uint256 _token1PurchaseFeeAmount);
149
150 function getAmount0Out(
151 uint256 _amount1In,
152 uint256 _token0OverToken1Price,
153 uint256 _token0PurchaseFee
154 ) external pure returns (uint256 _amount0Out, uint256 _token0PurchaseFeeAmount);
155
156 function getAmount1In(
157 uint256 _amount0Out,
158 uint256 _token0OverToken1Price,
159 uint256 _token0PurchaseFee
160 ) external pure returns (uint256 _amount1In, uint256 _token0FeeAmount);
161
162 function getAmount1Out(
163 uint256 _amount0In,
164 uint256 _token0OverToken1Price,
165 uint256 _token1PurchaseFee
166 ) external pure returns (uint256 _amount1Out, uint256 _token1PurchaseFeeAmount);
167
168 function getAmountsIn(uint256 _amountOut, address[] memory _path) external view returns (uint256[] memory _amounts);
169
170 function getAmountsOut(uint256 _amountIn, address[] memory _path) external view returns (uint256[] memory _amounts);
171
172 function getPrice() external view returns (uint256 _currentPrice);
173
174 function getPrice(uint256 _timestamp) external view returns (uint256 _price);
175
176 function getPriceNormalized() external view returns (uint256 _normalizedPrice);
177
178 function getRoleMembers(string memory _role) external view returns (address[] memory _members);
179
180 function hasRole(string memory _role, address _address) external view returns (bool);
181
182 function implementationAddress() external view returns (address);
183
184 function initialize(InitializeParams memory _params) external;
185
186 function isPaused() external view returns (bool);
187
188 function maxAnnualizedInterestRate() external view returns (int256);
189
190 function maxBasePrice() external view returns (uint256);
191
192 function maxToken0PurchaseFee() external view returns (uint256);
193
194 function maxToken1PurchaseFee() external view returns (uint256);
195
196 function minAnnualizedInterestRate() external view returns (int256);
197
198 function minBasePrice() external view returns (uint256);
199
200 function minToken0PurchaseFee() external view returns (uint256);
201
202 function minToken1PurchaseFee() external view returns (uint256);
203
204 function name() external view returns (string memory);
205
206 function perSecondInterestRate() external view returns (int256);
207
208 function priceLastUpdated() external view returns (uint256);
209
210 function proxyAdminAddress() external view returns (address);
211
212 function removeTokens(address _tokenAddress, uint256 _amount) external;
213
214 function requireValidPath(address[] memory _path, address _token0, address _token1) external pure;
215
216 function reserve0() external view returns (uint256);
217
218 function reserve1() external view returns (uint256);
219
220 function setApprovedSwappers(address[] memory _approvedSwappers, bool _setApproved) external;
221
222 function setFeeBounds(
223 uint256 _minToken0PurchaseFee,
224 uint256 _maxToken0PurchaseFee,
225 uint256 _minToken1PurchaseFee,
226 uint256 _maxToken1PurchaseFee
227 ) external;
228
229 function setFeeReceiver(address _feeReceiver) external;
230
231 function setOraclePriceBounds(
232 uint256 _minBasePrice,
233 uint256 _maxBasePrice,
234 int256 _minAnnualizedInterestRate,
235 int256 _maxAnnualizedInterestRate
236 ) external;
237
238 function setPaused(bool _setPaused) external;
239
240 function setTokenPurchaseFees(uint256 _token0PurchaseFee, uint256 _token1PurchaseFee) external;
241
242 function setTokenReceiver(address _tokenReceiver) external;
243
244 function swap(uint256 _amount0Out, uint256 _amount1Out, address _to, bytes memory _data) external;
245
246 function swapExactTokensForTokens(
247 uint256 _amountIn,
248 uint256 _amountOutMin,
249 address[] memory _path,
250 address _to,
251 uint256 _deadline
252 ) external returns (uint256[] memory _amounts);
253
254 function swapTokensForExactTokens(
255 uint256 _amountOut,
256 uint256 _amountInMax,
257 address[] memory _path,
258 address _to,
259 uint256 _deadline
260 ) external returns (uint256[] memory _amounts);
261
262 function sync() external;
263
264 function token0() external view returns (address);
265
266 function token0Decimals() external view returns (uint8);
267
268 function token0FeesAccumulated() external view returns (uint256);
269
270 function token0PurchaseFee() external view returns (uint256);
271
272 function token1() external view returns (address);
273
274 function token1Decimals() external view returns (uint8);
275
276 function token1FeesAccumulated() external view returns (uint256);
277
278 function token1PurchaseFee() external view returns (uint256);
279
280 function tokenReceiverAddress() external view returns (address);
281
282 function version() external pure returns (AgoraStableSwapPair.Version memory _version);
283}

ABI

The ABI of the AgorastableSwapPair is available here