Autoliquidity para Tokens Fuertototes

Ahmed Castro - May 11 '22 - - Dev Community

Siempre buscamos maneras de mantener nuestros ecosistemas saludables y a prueba de futuro. Para eso en este video agregamos al funcionalidad de Autoliquidez a un token ERC-20. Este sistema toma un porcentaje de cada transacción y lo agrega automáticamente al par de liquidez, respaldándolo con ether, o con cualquier otra moneda. Esto ayuda a darle la seguridad a los participantes del mercado que siempre y cuando el token esté en movimiento este estará respaldado con nueva liquidez.

https://www.youtube.com/watch?v=qII2ePpp-qA

Toma en cuenta que este material está dirigido para oyentes avanzados por lo que te recomendaría profundizar sobre cómo hacer swaps y cómo agregar liqudiez desde un smart contract luego de ver este video.

Antes de iniciar

Asegurate de instalar Metamask, conectar tu wallet a Polygon Mainnet y conseguir MATIC desde algún exchange. Pero este video es compatible también con cualquier blockchain compatible con la Ethereum Virtual Machine.

Lanzamos el contrato

Nota que debes seleccionar la wallet de liquidez (liquidityWallet) y el address correcto del router, este dependará de dónde deseas lanzar el contrato:

  • Polygon Quickswap: 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff
  • Ethereum Uniswap V2: 0x10ED43C718714eb63d5aA57B78B54704E256024E
  • BSC Mainnet Pancake: 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
  • BSC Testnet Pancake: 0xD99D1c33F9fC3444f8101754aBC46c52416550D1
// SPDX-License-Identifier: MIT

pragma solidity 0.8.13;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

interface IUniswapV2Router02 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external;
    function addLiquidityETH(
        address token,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );
}

interface IUniswapV2Factory {
    function createPair(address tokenA, address tokenB) external returns (address pair);
}

contract MyToken is ERC20
{
    address public liquidityWallet;

    IUniswapV2Router02 router;
    address public pair;

    uint public feeDecimal = 2;
    uint public feePercentage;

    uint256 public minTokensBeforeSwap;

    mapping(address => bool) public isTaxless;

    bool private isLocked;

    constructor () ERC20("My Token", "TKN")
    {
        router = IUniswapV2Router02(0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff);
        pair = IUniswapV2Factory(router.factory()).createPair(address(this), router.WETH());

        // Edit here
        liquidityWallet = 0x0000000000000000000000000000000000000000;
        uint supply = 1_000_000 ether;
        feePercentage = 100; // 1.00% tx fee
        minTokensBeforeSwap = 10 ether;
        // End edit

        isTaxless[msg.sender] = true;
        isTaxless[liquidityWallet] = true;
        isTaxless[address(this)] = true;
        isTaxless[address(0)] = true;

        _mint(msg.sender, supply);
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint amount
    ) internal virtual override(ERC20)
    {
        super._beforeTokenTransfer(from, to, amount);

        if(!isLocked)
        {
            isLocked = true;
            if(balanceOf(address(this)) >= minTokensBeforeSwap && from != pair)
                autoLiquidity();
            isLocked = false;
        }
    }

    function _afterTokenTransfer(
        address from,
        address to,
        uint amount
    ) internal virtual override(ERC20)
    {
        super._afterTokenTransfer(from, to, amount);

        if(!isLocked)
        {
            if (!isTaxless[from]) {
                uint feesCollected = calculateFee(amount);
                if(feesCollected > 0)
                {
                    isLocked = true;
                    _transfer(to, address(this), feesCollected);
                    isLocked = false;
                }
            }
        }
    }

    function autoLiquidity() internal
    {
        // Let's swap half collected tokens for eth
        uint amountToSwap = balanceOf(address(this)) / 2;

        address[] memory sellPath = new address[](2);
        sellPath[0] = address(this);
        sellPath[1] = router.WETH();       

        _approve(address(this), address(router), amountToSwap);
        router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            amountToSwap,
            0,
            sellPath,
            address(this),
            block.timestamp
        );

        // Now we are ready to send to LP
        uint256 amountETHLiquidity = address(this).balance;
        if(balanceOf(address(this)) > 0) {
            _approve(address(this), address(router), balanceOf(address(this)));
            router.addLiquidityETH{value: amountETHLiquidity}(
                address(this),
                balanceOf(address(this)),
                0,
                0,
                liquidityWallet,
                block.timestamp
            );
        }
    }

    function calculateFee(uint amount) internal view returns(uint) {
        return (amount * feePercentage)  / (10**(feeDecimal + 2));
    }

    fallback() external payable {}
    receive() external payable {}
}
Enter fullscreen mode Exit fullscreen mode

Gracias por ver este tutorial!

Sígannos en dev.to y en Youtube para todo lo relacionado al desarrollo en Blockchain en Español.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .