WEB3DEV

Cover image for Construindo um Contrato Inteligente de Pool de Liquidez para Troca de Tokens
Panegali
Panegali

Posted on

Construindo um Contrato Inteligente de Pool de Liquidez para Troca de Tokens

Explorando o Contrato Inteligente de Gerenciamento de Liquidez: Desmembramento das Funções

No mundo das finanças descentralizadas (DeFi), contratos inteligentes desempenham um papel fundamental ao permitir várias atividades financeiras. Um contrato desse tipo é o contrato inteligente Liquidity, projetado para gerenciar a provisão de liquidez e a troca de tokens entre dois tokens ERC-20, DOGE e USDT. Neste artigo, vamos analisar as funções-chave deste contrato para compreender seu funcionamento interno e as funcionalidades que ele oferece.

Foto de Jievani Weerasinghe no Unsplash

Função setAddresses(address _DOGE, address _usdt)

A função setAddresses() é usada pelo proprietário do contrato para definir os endereços dos tokens DOGE e USDT. Este passo é vital, pois estabelece a conexão entre o contrato e os tokens que ele irá gerenciar. As interfaces IERC20 são utilizadas para criar instâncias dos contratos de token.

function setAddresses(address _DOGE, address _usdt) public onlyOwner {
    DOGE = IERC20(_DOGE);
    USDT = IERC20(_usdt);
}
Enter fullscreen mode Exit fullscreen mode

Função getReserves()

A função getReserves() permite que terceiros externos obtenham as reservas atuais dos tokens DOGE e USDT dentro do contrato. Essas reservas são cruciais para diversos cálculos ao longo das operações do contrato, garantindo uma provisão de liquidez precisa e troca de tokens.

function getReserves()
    public
    view
    returns (uint256 _reserve1, uint256 _reserve2)
{
    _reserve1 = reserve1;
    _reserve2 = reserve2;
}
Enter fullscreen mode Exit fullscreen mode

Função quote(uint256 amountA, uint256 reserveA, uint256 reserveB)

A função quote() é usada internamente para calcular a cotação para a troca de tokens. Dado o valor desejado amountA para a troca e as reservas atuais dos tokens A (reserveA) e B (reserveB), esta função calcula o montante correspondente de token B que será recebido após a troca. Ela garante que haja liquidez suficiente para que a troca ocorra.

function quote(
    uint256 amountA,
    uint256 reserveA,
    uint256 reserveB
) internal pure returns (uint256) {
    require(amountA > 0, "UniswapV2Library: MONTANTE_INSUFICIENTE");
    require(
        reserveA > 0 && reserveB > 0,
        "UniswapV2Library: LIQUIDEZ_INSUFICIENTE"
    );
    uint256 amountB = amountA.mul(reserveB) / reserveA;
    return amountB;
}
Enter fullscreen mode Exit fullscreen mode

Função _addLiquidity(uint256 _DOGEQuantity, uint256 _USDTQuantity)

A função _addLiquidity() calcula os montantes ideais de DOGE e USDT a serem adicionadas para o fornecimento de liquidez. Ela leva em consideração as reservas e saldos atuais, bem como os montantes desejados de ambos os tokens. Os montantes calculados garantem que o pool de liquidez permaneça equilibrado e eficiente.

function _addLiquidity(
        uint256 _DOGEQuantity,
        uint256 _USDTQuantity
    ) internal view returns (uint256 amountA, uint256 amountB) {
        require(
            _DOGEQuantity != 0 && _USDTQuantity != 0,
            "montante do token não pode ser zero"
        );
        (uint256 reserveA, uint256 reserveB) = getReserves();
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (_DOGEQuantity, _USDTQuantity);
        } else {
            uint256 amount2Optimal = quote(_DOGEQuantity, reserveA, reserveB);
            if (amount2Optimal <= _USDTQuantity) {
                (amountA, amountB) = (_DOGEQuantity, amount2Optimal);
            } else {
                uint256 amountAOptimal = quote(
                    _USDTQuantity,
                    reserveB,
                    reserveA
                );
                assert(amountAOptimal <= _DOGEQuantity);
                (amountA, amountB) = (amountAOptimal, _USDTQuantity);
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

Função addLiquidity(uint256 amountDOGE, uint256 amountUSDT, address to)

A função addLiquidity() permite que os usuários depositem tokens DOGE e USDT para fornecer liquidez. Ela calcula os montantes ideais de tokens a serem adicionados usando a função _addLiquidity(), transfere os tokens do endereço do usuário para o contrato e emite tokens LP que representam a liquidez fornecida.

function addLiquidity(
        uint256 amountDOGE,
        uint256 amountUSDT,
        address to
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
        (amountA, amountB) = _addLiquidity(amountDOGE, amountUSDT);
        DOGE.safeTransferFrom(msg.sender, address(this), amountA);
        USDT.safeTransferFrom(msg.sender, address(this), amountB);
        liquidity = mintLPToken(to);
    }
Enter fullscreen mode Exit fullscreen mode

Função mintLPToken(address to)

A função mintLPToken() calcula o montante de tokens LP a serem emitidos quando a liquidez é adicionada. Ela garante que o montante inicial de liquidez atenda aos requisitos mínimos e distribui tokens LP proporcionalmente aos usuários.

function mintLPToken(address to) internal returns (uint256 liquidity) {
        (uint256 _reserve0, uint256 _reserve1) = getReserves(); // economia de gás
        uint256 balance0 = DOGE.balanceOf(address(this));
        uint256 balance1 = USDT.balanceOf(address(this));
        uint256 amount0 = balance0.sub(_reserve0);
        uint256 amount1 = balance1.sub(_reserve1);

        uint256 _totalLiquidity = totalLiquidity;
        if (_totalLiquidity == 0) {
            liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
            userLiquidity[address(0)] = MINIMUM_LIQUIDITY;
        } else {
            liquidity = Math.min(
                amount0.mul(_totalLiquidity) / _reserve0,
                amount1.mul(_totalLiquidity) / _reserve1
            );
        }
        require(liquidity > 0, "INSUFICIENTE_LIQUIDEZ_CUNHADA");
        userLiquidity[to] += liquidity;
        totalLiquidity += liquidity;
        reserve1 = DOGE.balanceOf(address(this));
        reserve2 = USDT.balanceOf(address(this));
    }
Enter fullscreen mode Exit fullscreen mode

Função burn(uint256 liquidity)

A função burn() calcula os montantes de tokens DOGE e USDT a serem devolvidos aos usuários quando a liquidez é removida. Ela determina a distribuição proporcional com base na liquidez fornecida e garante que ambos os tokens sejam devolvidos nos montantes adequados.

function burn(
        uint256 liquidity
    ) internal returns (uint256 amount0, uint256 amount1) {
        uint256 balance0 = DOGE.balanceOf(address(this));
        uint256 balance1 = USDT.balanceOf(address(this));
        uint256 _totalLiquidity = totalLiquidity;
        amount0 = liquidity.mul(balance0) / _totalLiquidity;
        amount1 = liquidity.mul(balance1) / _totalLiquidity; // a utilização dos saldos garante uma distribuição proporcional
        require(
            amount0 > 0 && amount1 > 0,
            "LIQUIDEZ_INSUFICIENTE_QUEIMADA: Aumente o montante de liquidez"
        );
        totalLiquidity -= liquidity;
    }
Enter fullscreen mode Exit fullscreen mode

Função removeLiquidity(uint256 liquidity, address to)

A função removeLiquidity() permite aos usuários remover a liquidez do pool. Ela calcula o montante de tokens DOGE e USDT a serem devolvidos ao usuário e transfere os tokens de acordo com isso. A liquidez do usuário é atualizada e a liquidez total e as reservas são ajustadas.

function removeLiquidity(
    uint256 liquidity,
    address to
) public returns (uint256 amountA, uint256 amountB) {
    require(
        userLiquidity[msg.sender] >= liquidity,
        "LIQUIDEZ_INSUFICIENTE"
    );
    (amountA, amountB) = burn(liquidity);

    DOGE.safeTransfer(to, amountA);

    USDT.safeTransfer(to, amountB);
    userLiquidity[msg.sender] -= liquidity;
    reserve1 = DOGE.balanceOf(address(this));
    reserve2 = USDT.balanceOf(address(this));
}
Enter fullscreen mode Exit fullscreen mode

Função swapDOGEForUSDT(uint256 amountIn, address _to)

A função swapDOGEForUSDT() facilita a troca de tokens DOGE por tokens USDT. Ela calcula o montante de tokens USDT a serem obtidos com base no montante de tokens DOGE de entrada e realiza a troca. As reservas do contrato são atualizadas adequadamente.

function swapDOGEForUSDT(uint256 amountIn, address _to) external {
    require(amountIn > 0, "MONTANTE_DE_ENTRADA_INSUFICIENTE");
    (uint256 reserveIn, uint256 reserveOut) = getReserves();

    require(
        reserveIn > 0 && reserveOut > 0,
        "UniswapV2Library: LIQUIDEZ_INSUFICIENTE"
    );
    uint256 amountInWithFee = amountIn.mul(997);
    uint256 numerator = amountInWithFee.mul(reserveOut);
    uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
    uint256 amountOut = numerator / denominator;
    require(amountOut <= reserveOut, "UniswapV2: LIQUIDEZ_INSUFICIENTE");
    DOGE.safeTransferFrom(_to, address(this), amountIn);
    USDT.safeTransfer(_to, amountOut);
    reserve1 = DOGE.balanceOf(address(this));
    reserve2 = USDT.balanceOf(address(this));
}
Enter fullscreen mode Exit fullscreen mode

Função swapUSDTForDOGE(uint256 amountIn, address _to)

A função swapUSDTForDOGE() permite aos usuários trocar tokens USDT por tokens DOGE. Semelhante à função anterior, ela calcula o montante de tokens DOGE a serem obtidos com base no montante de tokens USDT de entrada e realiza a troca, atualizando as reservas do contrato.

function swapUSDTForDOGE(uint256 amountIn, address _to) external {
    require(amountIn > 0, "MONTANTE_DE_ENTRADA_INSUFICIENTE");
    (uint256 reserveOut, uint256 reserveIn) = getReserves();
    require(
        reserveIn > 0 && reserveOut > 0,
        "UniswapV2Library: LIQUIDEZ_INSUFICIENTE"
    );
    uint256 amountInWithFee = amountIn.mul(997);
    uint256 numerator = amountInWithFee.mul(reserveOut);
    uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
    uint256 amountOut = numerator / denominator;
    require(amountOut <= reserveOut, "UniswapV2: LIQUIDEZ_INSUFICIENTE");
    USDT.safeTransferFrom(_to, address(this), amountIn);
    DOGE.safeTransfer(_to, amountOut);
    reserve1 = DOGE.balanceOf(address(this));
    reserve2 = USDT.balanceOf(address(this));
}
Enter fullscreen mode Exit fullscreen mode

Conclusão

O contrato inteligente Liquidity encapsula as funcionalidades necessárias para fornecer liquidez e trocar tokens dentro do ecossistema DeFi. Ao explorar o propósito e a operação de cada função, obtemos informações sobre as capacidades do contrato. É importante notar que essa explicação fornece uma compreensão de alto nível e a implementação real pode envolver considerações adicionais, como medidas de segurança e eficiência de gás. O contrato Liquidity exemplifica o poder dos contratos inteligentes na revolução das transações financeiras na blockchain.

Pode ver o código completo AQUI.

Apoie-nos AQUI.

Muito obrigado!


Artigo escrito por Rohit Goyal. Traduzido por Marcelo Panegali.

Top comments (0)