Uniswap V2 AMM
Uniswap V2 fork deployed on Celo Sepolia for token-to-token swaps.
Deployed Contracts
| Contract | Address |
|---|---|
| UniswapV2Factory | 0xe3FB7Da331c5420eac2D4c55c41B75Fc5B897c40 |
| UniswapV2Router02 | 0x5b724eEe9a2D4d76Ca0edFbAcf1B36749Eb7ed9b |
Active Pools
| Pair | Token0 | Token1 | Reserve0 | Reserve1 |
|---|---|---|---|---|
| IMC/USDT | 0xF150...d5A2 | 0x3C8E...DDDF | 1000 IMC | 500 USDT |
| IMC/USDC | 0xF150...d5A2 | 0x82DD...62A7 | 1000 IMC | 500 USDC |
| USDT/USDC | 0x3C8E...DDDF | 0x82DD...62A7 | 500 USDT | 500 USDC |
Fee
0.3% per swap (997/1000 multiplier). Configured in UniswapV2Library.sol.
Source Code
Located at:
stablecoin-contracts/contracts/uniswap/
├── UniswapV2Factory.sol
├── UniswapV2Router02.sol
├── UniswapV2Pair.sol
├── UniswapV2Library.sol
├── interfaces/
│ ├── IUniswapV2Factory.sol
│ ├── IUniswapV2Pair.sol
│ ├── IUniswapV2Router02.sol
│ ├── IFactoryForRouter.sol
│ └── IWETH9.sol
└── test/
├── ERC20.sol
└── MockWETH.solArchitecture Decision: factory.getPair() vs pairFor()
The standard Uniswap V2 Router uses UniswapV2Library.pairFor() which hashes tokenA + tokenB + init code hash. This approach requires the factory's INIT_CODE_PAIR_HASH to be baked into the library at compile time.
We chose factory.getPair() instead:
- Simpler: no init code hash management
- More flexible: works even if pair creation logic changes
- Tradeoff: slightly more gas per swap (extra external call)
- For testnet/dev this is acceptable
Modified in UniswapV2Router02.sol:
solidity
function _getPair(address tokenA, tokenB) internal view returns (address pair) {
pair = IFactoryForRouter(factory).getPair(tokenA, tokenB);
require(pair != address(0), "UniswapV2: PAIR_NOT_FOUND");
}Adding New Pools
- Deploy two ERC-20 tokens
- Call
createPair(tokenA, tokenB)on the Factory - Approve the Router to spend both tokens
- Call
addLiquidity()to seed the pool - Register
CELO_<SYMBOL>_CONTRACTin comet-engine env
Price Calculation
amountOut = amountIn * 997 * reserveOut / (reserveIn * 1000 + amountIn * 997)