A minimal Uniswap V2-style AMM DEX for Monad, built with Foundry.
| Contract | Purpose |
|---|---|
src/DexFactory.sol |
Deploys and indexes one DexPair per token pair (CREATE2). Holds the optional protocol-fee switch (feeTo). |
src/DexPair.sol |
Constant-product (x * y = k) pool for two ERC-20 tokens. The pair contract is itself the ERC-20 LP token. Swaps charge a 0.30% fee that accrues to LPs; TWAP price accumulators included. |
src/DexRouter.sol |
Stateless entry point: addLiquidity, removeLiquidity, swapExactTokensForTokens, swapTokensForExactTokens (multi-hop supported), plus quote helpers. |
src/WMON.sol |
Wrapped MON (WETH9-style). Wrap native MON to trade it on the DEX. |
src/mocks/MockERC20.sol |
Mintable ERC-20 for tests and testnet demos. |
Trading works exactly like Uniswap V2: LPs deposit both sides of a pair and
receive LP tokens; swappers trade against the pool's reserves and pay 0.30%,
which stays in the pool. If feeTo is set on the factory, 1/6 of the fee
growth is minted to that address as the protocol fee.
| Chain ID | RPC | Explorer | |
|---|---|---|---|
| Monad Testnet | 10143 | https://testnet-rpc.monad.xyz |
https://testnet.monadvision.com |
| Monad Mainnet | 143 | https://rpc.monad.xyz |
https://monadvision.com |
Both are preconfigured as monad_testnet / monad_mainnet in foundry.toml.
Deployed and verified on both Monadscan and MonadVision:
| Contract | Address |
|---|---|
| WMON | 0xBeC7f7D06b75b6cbDE340440B6419C23b3C9bc67 |
| DexFactory | 0x8dae2b96dE2DAbDa5a1Ad1ed6157046D9019083b |
| DexRouter | 0xdf5F0C7e6f3b9BCF4d2B34909F3eC78F2D398a72 |
| Demo pair (KTA/KTB) | 0x7992A6F8b39d77D2C54dc4849f73d72a428dB61D |
Demo tokens: KTA 0xe9b877a4E4ebe261a716ECAe16aDa95bd1F6cB09, KTB 0x30050f6e132B028B9185122334fdB462e9B35C39 (both MockERC20 with public mint).
forge build
forge test- Get testnet MON from the faucet.
cp .env.example .envand fill inPRIVATE_KEY(or use a keystore instead).- Deploy:
source .env
forge script script/Deploy.s.sol --rpc-url monad_testnet --broadcastThe script deploys WMON, DexFactory, and DexRouter and prints their
addresses. For mainnet, swap in --rpc-url monad_mainnet.
Set the deployed addresses:
export FACTORY=0x... ROUTER=0x... WMON=0x...Deploy two demo tokens and mint yourself some supply:
export TKA=$(forge create src/mocks/MockERC20.sol:MockERC20 --rpc-url monad_testnet --private-key $PRIVATE_KEY --broadcast --constructor-args "Token A" TKA | awk '/Deployed to:/ {print $3}')
export TKB=$(forge create src/mocks/MockERC20.sol:MockERC20 --rpc-url monad_testnet --private-key $PRIVATE_KEY --broadcast --constructor-args "Token B" TKB | awk '/Deployed to:/ {print $3}')
cast send $TKA "mint(address,uint256)" $YOUR_ADDRESS 1000000ether --rpc-url monad_testnet --private-key $PRIVATE_KEY
cast send $TKB "mint(address,uint256)" $YOUR_ADDRESS 1000000ether --rpc-url monad_testnet --private-key $PRIVATE_KEYAdd liquidity (creates the pair automatically):
cast send $TKA "approve(address,uint256)" $ROUTER 10000ether --rpc-url monad_testnet --private-key $PRIVATE_KEY
cast send $TKB "approve(address,uint256)" $ROUTER 10000ether --rpc-url monad_testnet --private-key $PRIVATE_KEY
cast send $ROUTER "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)" \
$TKA $TKB 1000ether 4000ether 0 0 $YOUR_ADDRESS $(($(date +%s) + 600)) \
--rpc-url monad_testnet --private-key $PRIVATE_KEYSwap 1 TKA for TKB:
cast send $ROUTER "swapExactTokensForTokens(uint256,uint256,address[],address,uint256)" \
1ether 0 "[$TKA,$TKB]" $YOUR_ADDRESS $(($(date +%s) + 600)) \
--rpc-url monad_testnet --private-key $PRIVATE_KEYQuote a swap without sending it:
cast call $ROUTER "getAmountsOut(uint256,address[])(uint256[])" 1ether "[$TKA,$TKB]" --rpc-url monad_testnetWrap/unwrap native MON:
cast send $WMON "deposit()" --value 10ether --rpc-url monad_testnet --private-key $PRIVATE_KEY
cast send $WMON "withdraw(uint256)" 10ether --rpc-url monad_testnet --private-key $PRIVATE_KEYA Next.js + wagmi/RainbowKit UI for the DEX lives in web/ — swap,
add/remove liquidity, and mint demo tokens (KTA/KTB) against the live testnet
deployment above.
Live at https://kimi-dex.vercel.app
Run locally:
cd web
npm install
npm run dev- The router is token-to-token only; wrap MON into WMON first to trade it.
- Solidity 0.8.28,
evm_version = cancun. - Not audited. For learning and testnet use.