← Back to Work

Engineering Case Study

AMM DEX Aggregator

DeFi Protocol Engineering

A decentralized exchange aggregation project that compares swap pricing across two independent automated market makers and routes execution toward the Aggregator-selected quote.

Completed Engineering Project Public Source Sepolia Demo · Verified AMM Mechanics

Overview

This project implements two independent AMM contracts, ERC-20-style demo tokens (DAPP / USD), an on-chain Aggregator for quote comparison across those pools, and a React dApp that connects a wallet, reads quotes, and submits swaps and liquidity transactions through Ethers.js.

Aggregation here means single-hop comparison across two AMMs — not multi-hop routing, split routing, or a production DEX aggregator graph.

Real Product UI Public Demo
AMM DEX Aggregator interface showing Aggregator price comparison and Swap workflow
Swap + Aggregator interface Live UI showing AMM #1 / AMM #2 price comparison, token selection, and swap submission

Engineering Problem

Independent AMM pools can produce different swap outcomes for the same token pair because reserve balances and liquidity depth differ. Manually checking each pool is error-prone and slow.

The engineering goal is to query multiple liquidity sources, compare expected pricing, and direct a single-hop swap toward the route selected by the comparison logic — while keeping market logic on-chain and wallet interaction in the application layer.

My Role

DeFi Protocol Engineering · Full-Stack dApp

I implemented and integrated the public project end-to-end: Solidity contracts (Token, AMM, Aggregator), Hardhat deployment configuration, React application surfaces for swap/deposit/withdraw, MetaMask wallet connection, and Ethers.js contract reads/writes.

This is an engineering demonstration project with public source and demo — not a claim of production DEX operations or production liquidity.

Each AMM contract tracks token-pair reserves and prices swaps from the current reserve ratio:

amountOut = amountIn × reserveOut / reserveIn

This is simplified reserve-ratio pricing suitable for demonstrating liquidity-driven quote differences across independent pools. It is not a Uniswap-style invariant-preserving constant-product curve with (reserveIn + amountIn) in the denominator, and the contracts do not implement a swap fee.

Reserves Token A Reserve
Token B Reserve
Price getPrice → (reserveA × 1e18) / reserveB
Swap amountOut = amountIn × reserveOut / reserveIn · then update reserves
  • Independent AMM1 and AMM2 contracts with shared Token pair support Implemented
  • Reserve reads via getReserves / getPrice Implemented
  • Swap fee curve / Uniswap v2 invariant pricing Not Supported

The Aggregator contract is constructed with exactly two AMM instances (AMM1, AMM2). getPriceData is a view call that queries each AMM’s getPrice, skips pools that revert (no liquidity), and returns the selected lower-price comparison result with the corresponding AMM name.

The Aggregator contract provides on-chain quote comparison across AMM1 and AMM2. The frontend uses the returned comparison to select that AMM, approves it, and executes the swap directly against the selected AMM contract. Quote comparison therefore exists as an on-chain view (getPriceData) while live execution is a selected-AMM swap after allowance approval — not Aggregator.performSwap as the verified frontend path.

User selects pair + amount
Aggregator / UI queries AMM1 getPrice
Aggregator / UI queries AMM2 getPrice
Expected prices compared · selected quote chosen
Wallet confirms · single-hop swap on selected AMM
  • Two-AMM quote comparison Implemented
  • Single-hop execution on one selected AMM Implemented
  • Multi-hop routing · split routing · path graph optimization Not Supported

Contract Architecture

Deployment wires demo tokens, two AMM pools, and one Aggregator that references both AMMs.

Application React dApp · MetaMask · Ethers.js
Aggregator Aggregator.sol · getPriceData (quote comparison)
Liquidity Sources
  • AMM1 (AMM.sol)
  • AMM2 (AMM.sol)
Tokens
  • Token.sol · DAPP
  • Token.sol · USD

Swap Execution Flow

Read-only quote calls are separated from state-changing transactions.

Connect wallet (MetaMask)
Read reserves / prices (view)
Compare AMM1 vs AMM2 output pricing
Approve input token allowance
Submit swap transaction
Contract updates reserves · transfer tokens
UI refreshes balances / exchange rate

AMM.addLiquidity and AMM.removeLiquidity transfer tokens and update shared reserve/liquidity mappings for a token pair. The dApp exposes Deposit and Withdraw tabs for these flows.

Liquidity accounting is simplified: the current contracts do not mint ERC-20 LP share tokens or implement production-grade per-provider share math. Treat this as an engineering demonstration of reserve updates, not a production LP system.

The React application loads network-specific addresses from config (Hardhat 31337 and Sepolia 11155111), connects MetaMask via Ethers.js, and uses contract ABIs for Token / AMM / Aggregator reads and writes. Core surfaces include Swap, Deposit, Withdraw, Charts, network selection, and wallet connect.

  • React application
  • Ethers.js provider / signer
  • MetaMask connection
  • ABI-backed contract calls
  • Quote / price reads
  • Approve + swap transactions
  • Balance refresh after txs

Security & Reliability

Supported contract-level checks include Solidity 0.8 arithmetic safety, token transfer/allowance validation, zero-address rejection on token transfer/approve paths, and require-guards when a pair has no liquidity.

  • Solidity ^0.8 checked arithmetic
  • ERC-20-style allowance + transferFrom for swaps/liquidity
  • No-liquidity require on swap / getPrice
  • Zero-address checks on Token transfer / approve

Slippage limits, deadlines, reentrancy guards, and swap fees are not implemented. This project demonstrates AMM and routing mechanics and should not be interpreted as a production-hardened DEX.

Engineering Decisions

Two independent AMM contracts
Separate reserve states create meaningful quote differences for the same token pair — the prerequisite for aggregation.
Reserve-ratio swap pricing
Deterministic, easy-to-reason pricing from current reserves; chosen to demonstrate liquidity-driven execution differences rather than full Uniswap invariant mechanics.
On-chain Aggregator quotes + selected-AMM execution
getPriceData centralizes comparison on-chain; the dApp then approves and swaps on the Aggregator-selected AMM so user allowances and transfers align with the selected pool.
Solidity + Hardhat
Core market logic and deployment tooling for local Hardhat and Sepolia-configured networks.
React + Ethers.js
Bridges wallet signing, quote reads, approvals, and state-changing transactions into a usable swap workflow.

What I Personally Built

  • Token, AMM, and Aggregator Solidity contracts Smart Contracts · Implemented
  • Two-AMM price comparison and single-hop selection logic Routing Logic · Implemented
  • React swap / deposit / withdraw application surfaces Frontend · Implemented
  • MetaMask connection, approvals, and Ethers.js contract calls Wallet Integration · Implemented
  • Hardhat deploy scripts and network address config (local + Sepolia) Deployment · Implemented
  • Hardhat test suite present in repo (interface drift vs current AMM API) Testing · Partial

Technology

  • Solidity
  • Ethereum / EVM
  • Hardhat
  • Ethers.js
  • React
  • JavaScript
  • Node.js

Current Status

Completed Engineering Project · Public Source · Sepolia Demo · Verified

Available

  • Public GitHub repository
  • Public Vercel demo (Sepolia)
  • Local Hardhat + Sepolia address configuration
  • Verified Sepolia quote comparison + selected-AMM swap

Scope

  • Educational / engineering implementation
  • Two-AMM single-hop aggregation
  • Not a production DEX, mainnet deployment, or production users