CORE DEFI PRIMITIVES AND MECHANICS

Building Oracle-Free Automated Market Makers From Scratch

6 min read
#DeFi #Smart Contracts #Liquidity #Protocol Design #AMM
Building Oracle-Free Automated Market Makers From Scratch

Introduction

Decentralized finance has been revolutionized by automated market makers, or AMMs, which allow users to trade assets without needing a counterparty. The majority of popular AMMs rely on external price oracles to determine the fair value of assets, yet this dependency introduces a single point of failure and an additional layer of complexity. In this article we explore how to build an oracle‑free AMM that does not require any external oracle input. By carefully structuring the pricing logic, fee schedule, and liquidity incentives, a self‑contained AMM can provide reliable price discovery, robust liquidity, and strong security guarantees. We will walk through the core principles, the mathematical underpinnings, and the practical steps needed to implement such a system from scratch on a blockchain like Ethereum or Solana.

Why Build an Oracle‑Free AMM?

An oracle‑free design eliminates several common pain points:

  • Security: External oracles can be compromised or manipulated. By removing the oracle dependency the attack surface shrinks dramatically.
  • Simplicity: Contract code becomes leaner, easier to audit, and cheaper to deploy.
  • Privacy: Oracle queries can leak sensitive trade information. Self‑contained pricing keeps all relevant data on chain.
  • Resilience: The system no longer depends on an off‑chain service that may be unavailable or misbehave.

The trade‑off is that the AMM must internally generate a price signal that reflects market reality. The most proven way to do this is through constant product or constant sum invariant curves that tie the pool’s token balances to the price implicitly.

Core Design Concepts

Token Pairs and Pool Structure

An AMM pool holds two tokens, A and B. Users can deposit or withdraw liquidity as a pair of these tokens, receiving or redeeming liquidity provider (LP) tokens in exchange. The pool’s state is defined by the current reserves of each token, denoted (R_A) and (R_B).

Invariant Curve

The invariant is a function (f(R_A, R_B) = k) that remains constant after any trade. The most common choice is the constant product invariant:

[ R_A \times R_B = k ]

This equation ensures that any change in one reserve must be compensated by an opposite change in the other, thereby setting the price implicitly.

Price Determination

The marginal price of token A in terms of token B is derived by differentiating the invariant. For the constant product model the price is simply:

[ P_{A/B} = \frac{R_B}{R_A} ]

Because the reserves change with each trade, the price evolves naturally with supply and demand, removing the need for an external oracle.

Fees and Incentives

To keep liquidity flowing, the AMM charges a fee on every trade. The fee is typically a small percentage of the input amount and is added to the reserves, thereby increasing the invariant (k). This fee is not paid out to LPs directly; instead, LPs benefit from the growth in the pool value over time. In a fully autonomous design we can also add incentive tokens or governance rights to LPs to further encourage participation.

Mathematical Foundations

Constant Product Invariant

The constant product invariant guarantees that the pool can always provide a price that satisfies the equation (R_A \times R_B = k). When a trader swaps (x) units of token A for token B, the new reserves become:

[ R_A' = R_A + x ] [ R_B' = \frac{k}{R_A'} = \frac{R_A R_B}{R_A + x} ]

The amount of token B the trader receives is:

[ y = R_B - R_B' = R_B - \frac{R_A R_B}{R_A + x} ]

Subtracting the fee (f) from the input (x) (e.g., (f = 0.3%) of (x)) yields the effective input amount:

[ x_{\text{eff}} = x (1 - f) ]

This calculation is performed in a single transaction, ensuring atomicity.

Slippage Calculation

Slippage quantifies how much the execution price deviates from the mid‑market price. For the constant product model the slippage for a trade of size (x) is:

[ \text{Slippage} = 1 - \frac{R_B - y}{R_B} = 1 - \frac{R_A}{R_A + x_{\text{eff}}} ]

Providing a formula helps users estimate the impact before committing.

Liquidity Provision Impact

When a liquidity provider adds equal value amounts of token A and token B, the invariant (k) increases proportionally. LP tokens represent a share of the pool’s total value, so the value of an LP token is:

[ \text{LP token value} = \frac{R_A + R_B}{\text{total LP supply}} ]

Since fees accumulate in the reserves, the pool’s value grows, rewarding LPs automatically.

Building the Smart Contract

Below we outline the essential components of an oracle‑free AMM contract. The example is written in Solidity‑like pseudocode; adjust syntax to your target chain.

State Variables

address public tokenA;
address public tokenB;
uint256 public reserveA;
uint256 public reserveB;
uint256 public totalSupply; // LP token supply
uint256 public feeNumerator = 3; // 0.3%
uint256 public feeDenominator = 1000;

Constructor

constructor(address _tokenA, address _tokenB) {
    tokenA = _tokenA;
    tokenB = _tokenB;
}

Minting Liquidity

function addLiquidity(uint256 amountA, uint256 amountB) external returns (uint256 lpTokens) {
    // Transfer tokens from user to contract
    IERC20(tokenA).transferFrom(msg.sender, address(this), amountA);
    IERC20(tokenB).transferFrom(msg.sender, address(this), amountB);

    if (totalSupply == 0) {
        // Initial liquidity: set reserves directly
        reserveA = amountA;
        reserveB = amountB;
        lpTokens = sqrt(amountA * amountB);
        totalSupply = lpTokens;
        _mint(msg.sender, lpTokens);
    } else {
        // Calculate shares based on existing reserves
        uint256 shareA = (amountA * totalSupply) / reserveA;
        uint256 shareB = (amountB * totalSupply) / reserveB;
        lpTokens = min(shareA, shareB);
        totalSupply += lpTokens;
        reserveA += amountA;
        reserveB += amountB;
        _mint(msg.sender, lpTokens);
    }
}

Swapping Tokens

function swapAtoB(uint256 amountIn) external returns (uint256 amountOut) {
    uint256 fee = (amountIn * feeNumerator) / feeDenominator;
    uint256 amountInAfterFee = amountIn - fee;
    uint256 newReserveA = reserveA + amountInAfterFee;
    uint256 newReserveB = (reserveA * reserveB) / newReserveA;
    amountOut = reserveB - newReserveB;

    // Update reserves
    reserveA = newReserveA;
    reserveB = newReserveB;

    // Transfer tokens
    IERC20(tokenA).transferFrom(msg.sender, address(this), amountIn);
    IERC20(tokenB).transfer(msg.sender, amountOut);
}

Removing Liquidity

function removeLiquidity(uint256 lpAmount) external returns (uint256 amountA, uint256 amountB) {
    require(lpAmount <= balanceOf(msg.sender), "Insufficient LP balance");
    uint256 share = (lpAmount * 1e18) / totalSupply; // use 18 decimals for precision
    amountA = (reserveA * share) / 1e18;
    amountB = (reserveB * share) / 1e18;

    // Update state
    reserveA -= amountA;
    reserveB -= amountB;
    totalSupply -= lpAmount;
    _burn(msg.sender, lpAmount);

    // Transfer tokens back to user
    IERC20(tokenA).transfer(msg.sender, amountA);
    IERC20(tokenB).transfer(msg.sender, amountB);
}

View Functions

function getPrice() external view returns (uint256 price) {
    return (reserveB * 1e18) / reserveA; // price of A in B with 18 decimals
}

Security Considerations

  1. Reentrancy: Protect state updates before external calls. Use nonReentrant modifier or transfer pattern. For more on safe patterns, see the secrets of creating stable, oracle‑free liquidity pools.
  2. Integer Overflows: Use safe math libraries or Solidity 0.8+ built‑in checks.
  3. Front‑Running: The invariant formula ensures that trades are atomic, but large orders may still be front‑run. Consider limiting max trade size or implementing a time‑weighted average price buffer if needed.
  4. Dust Removal: Handle very small balances carefully to avoid precision loss.

Testing Strategy

Unit Tests

  • Liquidity Addition: Verify reserves update correctly for both initial and subsequent deposits.
  • Swap Mechanics: Confirm the output amount matches the invariant calculation.
  • Fee Accumulation: Ensure fees are added to reserves and that LP token value increases accordingly.
  • Removal of Liquidity: Test proportional withdrawal and that balances are restored.

Integration Tests

Deploy the contract to a local testnet (e.g., Hardhat or Foundry) and simulate a sequence of trades and liquidity changes. Use fuzzing to inject random trade sizes and observe invariants hold.

Formal Verification

Model the invariant in a theorem prover (e.g., Coq or Lean). Prove that the swap function preserves the constant product property and that fees never reduce the invariant.

Real‑World Deployment

Once the contract passes all tests, deploy to a public chain. Consider the following steps:

  1. Deploy ERC‑20 Tokens: If the tokens are not standard, deploy ERC‑20 compatible versions.
  2. Reserve Initialization: Seed the pool with an initial liquidity to bootstrap trading.
  3. Community Governance: Optionally create a governance token to manage fee rates or upgrade paths.
  4. Auditing: Engage a third‑party auditor to review the code for security gaps. For best practices, refer to crafting decentralized exchanges without dependence on oracles.

Advanced Enhancements

Multi‑Token Pools

Expand the design to support more than two tokens by stacking multiple pair pools or adopting a meta‑AMM structure. Each pair still follows the constant product rule, and the pool can route trades through optimal paths.

Dynamic Fees

Instead of a fixed fee, allow the contract to adjust fees based on volatility or liquidity depth. This can be done by storing fee parameters that are modifiable by governance.

Liquidity Mining

Distribute a native incentive token to LPs proportionally to their share of the pool over time. This encourages long‑term liquidity provision.

Cross‑Chain Integration

Use a relayer or cross‑chain bridge to enable trades between assets on different blockchains while still maintaining an oracle‑free invariant within each chain.

Conclusion

Building an automated market maker that does not rely on external price oracles is both feasible and advantageous. By leveraging the constant product invariant, we can derive prices directly from on‑chain token balances, ensuring security, simplicity, and resilience. The design presented here walks through the essential mathematics, smart contract logic, and deployment considerations, providing a solid foundation for developers to create robust, self‑contained AMMs. As the DeFi ecosystem matures, oracle‑free solutions will play a critical role in reducing complexity and risk, fostering a more decentralized and trustworthy trading environment.

Sofia Renz
Written by

Sofia Renz

Sofia is a blockchain strategist and educator passionate about Web3 transparency. She explores risk frameworks, incentive design, and sustainable yield systems within DeFi. Her writing simplifies deep crypto concepts for readers at every level.

Discussion (6)

MA
Mario 1 month ago
Nice article, good insight on removing oracles. Will try this next week.
AU
Aurelia 1 month ago
The approach outlined seems promising, but I'm concerned about slippage in low liquidity pools. The paper lacks discussion on adaptive pool weighting during volatile periods.
NI
Nikolai 1 month ago
Aurelia, you’re right. I've seen similar issues in my own AMM testnets. Maybe incorporating time‑weighted pricing could help.
SA
Sam 1 month ago
Yo, this sounds cool but real life is messy. Anyone actually deployed a oracle‑free AMM yet? I'm skeptical.
JO
John 1 month ago
Sam, there’s a prototype on GitHub that I ran through. No oracle, just on‑chain data feeds. It works in a sandbox but I doubt it’s battle‑tested.
IV
Ivan 1 month ago
This proposal ignores the fact that oracle‑less models suffer from flash‑loan attacks. The math here assumes static reserves, which is unrealistic.
DM
Dmitri 3 weeks ago
Ivan, flash loans are a risk for all AMMs. The key is to design reserve curves that mitigate exploitation. I've been working on a hybrid curve that keeps slippage low.
AL
Alex 4 weeks ago
Great write‑up, but I think the article could delve deeper into fee structures. Dynamic fees based on pool volatility could offset oracle risks.
LU
Lucius 2 weeks ago
All in all, building from scratch gives you control, but don't underestimate the community adoption hurdle. You need incentives for liquidity providers.

Join the Discussion

Contents

Lucius All in all, building from scratch gives you control, but don't underestimate the community adoption hurdle. You need inc... on Building Oracle-Free Automated Market Ma... Oct 05, 2025 |
Alex Great write‑up, but I think the article could delve deeper into fee structures. Dynamic fees based on pool volatility co... on Building Oracle-Free Automated Market Ma... Sep 26, 2025 |
Ivan This proposal ignores the fact that oracle‑less models suffer from flash‑loan attacks. The math here assumes static rese... on Building Oracle-Free Automated Market Ma... Sep 25, 2025 |
Sam Yo, this sounds cool but real life is messy. Anyone actually deployed a oracle‑free AMM yet? I'm skeptical. on Building Oracle-Free Automated Market Ma... Sep 21, 2025 |
Aurelia The approach outlined seems promising, but I'm concerned about slippage in low liquidity pools. The paper lacks discussi... on Building Oracle-Free Automated Market Ma... Sep 20, 2025 |
Mario Nice article, good insight on removing oracles. Will try this next week. on Building Oracle-Free Automated Market Ma... Sep 18, 2025 |
Lucius All in all, building from scratch gives you control, but don't underestimate the community adoption hurdle. You need inc... on Building Oracle-Free Automated Market Ma... Oct 05, 2025 |
Alex Great write‑up, but I think the article could delve deeper into fee structures. Dynamic fees based on pool volatility co... on Building Oracle-Free Automated Market Ma... Sep 26, 2025 |
Ivan This proposal ignores the fact that oracle‑less models suffer from flash‑loan attacks. The math here assumes static rese... on Building Oracle-Free Automated Market Ma... Sep 25, 2025 |
Sam Yo, this sounds cool but real life is messy. Anyone actually deployed a oracle‑free AMM yet? I'm skeptical. on Building Oracle-Free Automated Market Ma... Sep 21, 2025 |
Aurelia The approach outlined seems promising, but I'm concerned about slippage in low liquidity pools. The paper lacks discussi... on Building Oracle-Free Automated Market Ma... Sep 20, 2025 |
Mario Nice article, good insight on removing oracles. Will try this next week. on Building Oracle-Free Automated Market Ma... Sep 18, 2025 |