1. Anasayfa
  2. 100 Günde Solidity

🧵 #100GündeSolidity 095 : Constant Product AMM (Sabit Ürün AMM)

🧵 #100GündeSolidity 095 : Constant Product AMM (Sabit Ürün AMM)
Constant Product AMM
0

Constant Product AMM (Sabit Ürün AMM)

Constant Product AMM, bir AMM (otomatik piyasa yapıcısı) türüdür ve tokenlerin sabit bir çarpım değerinde işlem görmesini sağlar. Bu işlemde, bir tokenin fiyatındaki artış, diğer tokenin fiyatında azalmaya neden olur ve XY = K formülü kullanılarak bu sabit ürün değeri korunur.

Constant Product AMM Nedir?

Constant Product AMM (Sabit Ürün AMM), otomatik piyasa yapıcısı (AMM) türlerinden biridir ve DeFi (Merkezi Olmayan Finans) protokollerinde sıklıkla kullanılır. Bu AMM türü, tokenlerin sabit bir çarpım değerinde işlem görmesini sağlar. Bu şekilde, bir tokenin fiyatındaki artış diğer tokenin fiyatında azalmaya neden olur ve sabit ürün değeri korunur. Bu işlem, XY = K formülü kullanılarak gerçekleştirilir.

Sabit Ürün Değeri Nasıl Korunur?

Constant Product AMM’de sabit ürün değeri, XY = K formülü kullanılarak korunur. Bu formülde X ve Y, işlem yapılan iki tokenin miktarlarını temsil eder. K, ise sabit ürün değerini ifade eder ve her zaman sabit kalır. Yani, X veya Y miktarı artarsa, diğer tokenin miktarı da azalır. Böylece, işlem sonucunda sabit ürün değeri korunur. Örneğin, bir kişi Ethereum (ETH) ve Dai (DAI) arasında bir işlem yapmak istediğinde, ETH miktarı artarsa, DAI miktarı da otomatik olarak azalır ve XY = K formülü ile sabit ürün değeri korunur.

XY = K Formülü Nasıl Çalışır?

XY = K formülü, Constant Product AMM’de sabit ürün değerini korumak için kullanılır. Bu formülde X ve Y, işlem yapılan iki tokenin miktarlarını ifade eder. K, ise sabit ürün değerini temsil eder ve sabit kalır. İşlem sırasında, bir kullanıcının bir tokeni satın almak için ödeme yapması gerektiğinde, bu tokenin fiyatı artar ve diğer tokenin fiyatı azalır. Bu, sabit ürün değerini korumak için X veya Y miktarlarında bir değişiklik yapılması anlamına gelir.

Örneğin, bir kullanıcı ETH ve DAI arasında işlem yapmak istediğinde, bir miktar ETH ödemek istediğinde, ETH miktarı artar ve DAI miktarı otomatik olarak azalır. Bu işlem sonucunda, XY = K formülü kullanılarak, ETH ve DAI’nin değeri sabit bir ürün değerinde kalır.

Bu formül, özellikle likidite havuzları gibi DeFi protokollerinde sıkça kullanılır ve AMM’lerin çalışma mantığına dayanır.

Constant Product AMM’nin Avantajları Nelerdir?

Constant Product AMM’nin birkaç avantajı vardır:

  1. Otomatik fiyat belirleme: Constant Product AMM, otomatik piyasa yapıcısı (AMM) türü olduğu için, işlem yapmak için bir alıcı veya satıcı bulmak zorunda değilsiniz. Bu, fiyatları otomatik olarak belirlemeyi ve anında işlem yapmayı mümkün kılar.
  2. Likidite Havuzlarını Artırır: Constant Product AMM, likidite havuzlarının artırılmasına yardımcı olur. İşlem yapmak için, likidite sağlayıcıları tarafından işlem yapılan iki tokenin havuzunda yeterli miktarda token olması gerekir. Bu sayede, kullanıcılar daha kolay ve hızlı bir şekilde işlem yapabilir.
  3. Sabit Ürün Değeri: Constant Product AMM, işlem yapılan tokenlerin sabit bir ürün değerinde olmasını sağlar. Bu, bir tokenin fiyatındaki artışın diğer tokenin fiyatındaki azalmaya neden olduğu için, kullanıcıların işlem yaparken risklerini azaltır.
  4. Yüksek Verimlilik: Constant Product AMM, düşük işlem ücretleri ile yüksek verimlilik sağlar. Bu, kullanıcıların daha düşük ücretlerle işlem yapmasını ve işlemlerin daha hızlı gerçekleşmesini sağlar.
  5. Anında İşlem: Constant Product AMM, anında işlem yapmayı mümkün kılar. İşlem yapmak için, sadece kullanıcıların havuzdaki iki token arasında bir işlem yapması gerekir. Bu, kullanıcıların daha hızlı ve daha kolay bir şekilde işlem yapmalarını sağlar.

Constant Product AMM ile İlgili Örnekler ve Kullanım Alanları

Constant Product AMM, likidite havuzlarının artırılmasına yardımcı olduğu için DeFi projelerinde ve merkezi olmayan borsalarda sıklıkla kullanılır. İşte birkaç örnek ve kullanım alanı:

  1. Uniswap: Uniswap, Constant Product AMM’nin en popüler örneğidir. Ethereum tabanlı bir DEX’dir ve kullanıcıların Ethereum ve diğer ERC-20 tokenleri arasında işlem yapmasına olanak tanır. Uniswap, likidite havuzları için sabit ürün değerini kullanır ve her işlem için %0.3 oranında bir işlem ücreti alır.
  2. Balancer: Balancer, birden fazla token ile ticaret yapmaya izin veren bir AMM platformudur. Kullanıcılar, likidite sağlayarak, havuzlarını %0.05 ile %0.25 arasında değişen bir ücret karşılığında yönetebilirler.
  3. Bancor: Bancor, Constant Product AMM’yi kullanarak tokenler arasında otomatik piyasa yapıcı olarak hizmet veren bir protokoldür. Bancor, kullanıcıların likidite sağlamasına ve bunun karşılığında havuzların yönetimine izin verir.
  4. Curve: Curve, Constant Product AMM’nin bir türevidir ve özellikle stabilcoinler (sabit değerli tokenler) arasında işlem yapmak için tasarlanmıştır. Curve, sabit ürün değeri için farklı bir matematiksel formül kullanır ve işlem ücretleri oldukça düşüktür.
  5. SushiSwap: SushiSwap, Uniswap’ın bir kopyasıdır ve Uniswap ile aynı Constant Product AMM işlem prensibini kullanır. SushiSwap, kullanıcıların likidite sağlamasına ve bunun karşılığında havuzların yönetimine izin verir.

Bu projelerin hepsi, likidite havuzları için sabit ürün değerini kullanarak otomatik piyasa yapıcısı olarak hizmet veren DeFi protokolleridir.

Akıllı Sözleşme Analizi

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract CPAMM {
    IERC20 public immutable token0;
    IERC20 public immutable token1;

    uint public reserve0;
    uint public reserve1;

    uint public totalSupply;
    mapping(address => uint) public balanceOf;

    constructor(address _token0, address _token1) {
        token0 = IERC20(_token0);
        token1 = IERC20(_token1);
    }

    function _mint(address _to, uint _amount) private {
        balanceOf[_to] += _amount;
        totalSupply += _amount;
    }

    function _burn(address _from, uint _amount) private {
        balanceOf[_from] -= _amount;
        totalSupply -= _amount;
    }

    function _update(uint _reserve0, uint _reserve1) private {
        reserve0 = _reserve0;
        reserve1 = _reserve1;
    }

    function swap(address _tokenIn, uint _amountIn) external returns (uint amountOut) {
        require(
            _tokenIn == address(token0) || _tokenIn == address(token1),
            "invalid token"
        );
        require(_amountIn > 0, "amount in = 0");

        bool isToken0 = _tokenIn == address(token0);
        (IERC20 tokenIn, IERC20 tokenOut, uint reserveIn, uint reserveOut) = isToken0
            ? (token0, token1, reserve0, reserve1)
            : (token1, token0, reserve1, reserve0);

        tokenIn.transferFrom(msg.sender, address(this), _amountIn);

        /*
        How much dy for dx?

        xy = k
        (x + dx)(y - dy) = k
        y - dy = k / (x + dx)
        y - k / (x + dx) = dy
        y - xy / (x + dx) = dy
        (yx + ydx - xy) / (x + dx) = dy
        ydx / (x + dx) = dy
        */
        // 0.3% fee
        uint amountInWithFee = (_amountIn * 997) / 1000;
        amountOut = (reserveOut * amountInWithFee) / (reserveIn + amountInWithFee);

        tokenOut.transfer(msg.sender, amountOut);

        _update(token0.balanceOf(address(this)), token1.balanceOf(address(this)));
    }

    function addLiquidity(uint _amount0, uint _amount1) external returns (uint shares) {
        token0.transferFrom(msg.sender, address(this), _amount0);
        token1.transferFrom(msg.sender, address(this), _amount1);

        /*
        How much dx, dy to add?

        xy = k
        (x + dx)(y + dy) = k'

        No price change, before and after adding liquidity
        x / y = (x + dx) / (y + dy)

        x(y + dy) = y(x + dx)
        x * dy = y * dx

        x / y = dx / dy
        dy = y / x * dx
        */
        if (reserve0 > 0 || reserve1 > 0) {
            require(reserve0 * _amount1 == reserve1 * _amount0, "x / y != dx / dy");
        }

        /*
        How much shares to mint?

        f(x, y) = value of liquidity
        We will define f(x, y) = sqrt(xy)

        L0 = f(x, y)
        L1 = f(x + dx, y + dy)
        T = total shares
        s = shares to mint

        Total shares should increase proportional to increase in liquidity
        L1 / L0 = (T + s) / T

        L1 * T = L0 * (T + s)

        (L1 - L0) * T / L0 = s 
        */

        /*
        Claim
        (L1 - L0) / L0 = dx / x = dy / y

        Proof
        --- Equation 1 ---
        (L1 - L0) / L0 = (sqrt((x + dx)(y + dy)) - sqrt(xy)) / sqrt(xy)
        
        dx / dy = x / y so replace dy = dx * y / x

        --- Equation 2 ---
        Equation 1 = (sqrt(xy + 2ydx + dx^2 * y / x) - sqrt(xy)) / sqrt(xy)

        Multiply by sqrt(x) / sqrt(x)
        Equation 2 = (sqrt(x^2y + 2xydx + dx^2 * y) - sqrt(x^2y)) / sqrt(x^2y)
                   = (sqrt(y)(sqrt(x^2 + 2xdx + dx^2) - sqrt(x^2)) / (sqrt(y)sqrt(x^2))
        
        sqrt(y) on top and bottom cancels out

        --- Equation 3 ---
        Equation 2 = (sqrt(x^2 + 2xdx + dx^2) - sqrt(x^2)) / (sqrt(x^2)
        = (sqrt((x + dx)^2) - sqrt(x^2)) / sqrt(x^2)  
        = ((x + dx) - x) / x
        = dx / x

        Since dx / dy = x / y,
        dx / x = dy / y

        Finally
        (L1 - L0) / L0 = dx / x = dy / y
        */
        if (totalSupply == 0) {
            shares = _sqrt(_amount0 * _amount1);
        } else {
            shares = _min(
                (_amount0 * totalSupply) / reserve0,
                (_amount1 * totalSupply) / reserve1
            );
        }
        require(shares > 0, "shares = 0");
        _mint(msg.sender, shares);

        _update(token0.balanceOf(address(this)), token1.balanceOf(address(this)));
    }

    function removeLiquidity(
        uint _shares
    ) external returns (uint amount0, uint amount1) {
        /*
        Claim
        dx, dy = amount of liquidity to remove
        dx = s / T * x
        dy = s / T * y

        Proof
        Let's find dx, dy such that
        v / L = s / T
        
        where
        v = f(dx, dy) = sqrt(dxdy)
        L = total liquidity = sqrt(xy)
        s = shares
        T = total supply

        --- Equation 1 ---
        v = s / T * L
        sqrt(dxdy) = s / T * sqrt(xy)

        Amount of liquidity to remove must not change price so 
        dx / dy = x / y

        replace dy = dx * y / x
        sqrt(dxdy) = sqrt(dx * dx * y / x) = dx * sqrt(y / x)

        Divide both sides of Equation 1 with sqrt(y / x)
        dx = s / T * sqrt(xy) / sqrt(y / x)
           = s / T * sqrt(x^2) = s / T * x

        Likewise
        dy = s / T * y
        */

        // bal0 >= reserve0
        // bal1 >= reserve1
        uint bal0 = token0.balanceOf(address(this));
        uint bal1 = token1.balanceOf(address(this));

        amount0 = (_shares * bal0) / totalSupply;
        amount1 = (_shares * bal1) / totalSupply;
        require(amount0 > 0 && amount1 > 0, "amount0 or amount1 = 0");

        _burn(msg.sender, _shares);
        _update(bal0 - amount0, bal1 - amount1);

        token0.transfer(msg.sender, amount0);
        token1.transfer(msg.sender, amount1);
    }

    function _sqrt(uint y) private pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }

    function _min(uint x, uint y) private pure returns (uint) {
        return x <= y ? x : y;
    }
}

interface IERC20 {
    function totalSupply() external view returns (uint);

    function balanceOf(address account) external view returns (uint);

    function transfer(address recipient, uint amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint amount);
    event Approval(address indexed owner, address indexed spender, uint amount);
}

Bu, bir Constant Product Automated Market Maker (CPAMM) sözleşmesidir. Bu sözleşme, kullanıcıların iki ERC-20 jetonunu takas etmelerine ve likidite eklemelerine olanak tanır. Bu sözleşme, jetonların arzını ve talebini kullanarak likiditeyi yönetir ve alım satım işlemlerinde fiyat belirlemeye dayanır.

Sözleşme, IERC20 arayüzünü uygular ve token0 ve token1 adlı iki adet IERC20 örneğine sahiptir. Bu örnekler, sözleşmeye eklenen iki jetonu temsil eder. Sözleşme, her bir jetonun rezervini, toplam arzı ve her kullanıcının hesabında bulunan jeton miktarını takip eder.

Sözleşme, iki adet özel işleve sahiptir: swap ve addLiquidity. swap işlevi, kullanıcılara belirli bir jetonu belirli bir miktarda başka bir jetona takas etme imkanı verir. addLiquidity işlevi, kullanıcılara bir jeton çifti için likidite eklemelerine olanak tanır.

swap işlevi, kullanıcının takas yapmak istediği jetonun adresini ve takas etmek istediği miktarı alır. Ardından, sözleşme, girdi olarak alınan tokenIn parametresini token0 veya token1 ile karşılaştırır ve geçerli olup olmadığını kontrol eder. Geçerliyse, isToken0 değişkeni belirlenir ve değişkenlerin doğru atamaları yapılır.

Daha sonra, işlev, tokenIn örneğinden _amountIn kadar token toplar. Sözleşme, ardından, çıktı olarak belirli bir miktarı vermek için jeton0 ve jeton1 rezervlerini nasıl güncelleyeceğini belirler.

addLiquidity işlevi, iki girdi miktarı ile çağrılır ve her bir jeton için kullanıcıdan gerekli miktarda jeton toplanır. Sözleşme, likiditeyi hesaplamak için yeni rezervlerle birlikte önceki rezervleri kullanır. Eğer rezerv0 veya rezerv1 sıfırdan farklı ise, işlev girdi olarak verilen miktarların birbirlerine oranı kontrol edilir. Eğer oran, mevcut orana eşit değilse, işlem başarısız olur.

addLiquidity işlevi, ardından kullanıcının yeni likidite paylarına sahip olması için gereken payları hesaplar ve bu payları kullanıcının hesabına verir.

Bu akıllı sözleşme, iki kişi arasında bir işlem gerçekleştirilmesini otomatikleştirmek için kullanılabilir. İşlevsel açıdan, sözleşme, belirli bir şart yerine getirildiğinde belirli bir eylem gerçekleştirir. Bu eylem, ödeme yapmak veya diğer kaynakları serbest bırakmak gibi herhangi bir işlem olabilir. Sözleşme, doğru şekilde programlandığı takdirde, belirtilen şartların yerine getirilip getirilmediğini otomatik olarak kontrol edebilir ve eylemi gerçekleştirebilir.

Süreç açısından, akıllı sözleşme, işlemin gerçekleşmesi için gereken tüm adımları otomatikleştirir. Bu, herhangi bir insan müdahalesine gerek kalmadan işlemin gerçekleştirilmesini sağlar. Bu da işlem sürecinin hızlandırılmasına ve hataların azaltılmasına yardımcı olabilir.

Güvenlik açısından, akıllı sözleşme, blockchain teknolojisi kullanılarak oluşturulduğundan, işlemlerin güvenli bir şekilde yapılmasını sağlar. Sözleşme, blockchain teknolojisi sayesinde değiştirilemez ve doğrulanabilir bir kayıt olarak kaydedilir. Bu, işlemin gerçekleştirildiği zamandaki tüm detayların geriye dönük olarak izlenebilir olmasını sağlar.

Ancak, akıllı sözleşmelerin programlama hatalarından kaynaklanan riskleri olabilir. Örneğin, kodun doğru şekilde yazılmaması veya belirli koşulların yanlış programlanması nedeniyle, yanlış eylemler gerçekleştirilebilir veya işlemler bloke edilebilir. Bu nedenle, akıllı sözleşmelerin yazılım hatalarından kaynaklanabilecek riskleri minimize etmek için doğru bir şekilde programlanması ve test edilmesi gerekir.

Solidity Programlama Dili Öğrenme yolculuğunuz hakkında daha iyi rehberlik almak için Solidity nedir? Ethereum Akıllı Sözleşmelerinin Dili Rehberi içeriğimize göz atın. Dilerseniz Yeni Başlayanlar için Solidity – Akıllı Sözleşme Geliştirme Hızlandırılmış Kursuna katılın.

Çalışmaya nereden başlayacağım diyenler için Blockchain ​​Developer Olmak İçin Yol Haritası içeriğine de muhakkak bakın.

Gelin aklınızdaki soruları SUPERPEER sohbetinde cevaplayalım.

Bu makaleyi okuduğunuz için teşekkürler! Bana destek olmak isterseniz;

Beni TwitterLinkedin ve YouTube‘da takip edin.

Kısa bir yorum bırakmayı UNUTMAYIN!

solidity101 - Solidity, 2015 yılında Christian Reitwiessner liderliğinde piyasaya sürülen, büyük harf kullanımına göre ikinci en büyük kripto para piyasası olan Ethereum tarafından oluşturulan yepyeni bir programlama dilidir.

Yazarın Profili
İlginizi Çekebilir

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir