DEV Community

Cover image for Autoliquidity para Tokens Fuertototes
Ahmed Castro
Ahmed Castro

Posted on • Updated on

Autoliquidity para Tokens Fuertototes

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.

Top comments (4)

Collapse
 
beboobs profile image
Beboobs

Hola Ahmed. Este contrato que propones peta en remix. No me lo despliega porque me fallan las lineas 54 y 55, si las ocmento me lo despliega correctamente. En entorno Shangai en remix y poniendo las direcciones de router de ethereum. podrias ayudarme?

Collapse
 
turupawn profile image
Ahmed Castro

Hola! El problema es que tenés que poner la dirección del router desplegado en esa chain. Por ejemplo:
Quickswap en Polygon
0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff
Uniswap en Mainnet
0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Pancake swap en BSC
0x10ED43C718714eb63d5aA57B78B54704E256024E

etc...

Collapse
 
majausone profile image
majausone

Hola Ahmed.
Estoy intentando entender la función addLiquidityETH.
Tienes un video explicando como agregar liquidez, pero es para addLiquidity no para addLiquidityETH.
Éstos son los parámetros:
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline

Tengo un erc20 que he definido asi:
ERC20 tokenTest = ERC20(0x7B4Be235433cB69b9a8301D8096EE118508E79b8);
Entonces en el adress token he puesto esto:
address(tokenTest),

El amountTokenDesired, no se que es lo que se me pide. A mi lo que me gustaría es enviar cierta cantidad de eth y en base a esa cantidad, que el contrato coja los tokens que necesite, pero aqui es como al revés no? o sea me pide tokens y en base a esa cantidad coge el eth?

En el amountTokenMin y amountETHMin he puesto 0.

En el address to, qué es lo que me pide? la adress que tiene el eth? yo es lo que he entendido, y como el contrato tiene eth lo que he puesto es:
address(this)

Saludos y gracias

Collapse
 
turupawn profile image
Ahmed Castro

El amountTokenDesired es la cantidad de los tokens erc-20 que agregaras como liquidez, y el to es quien recibe los LP tokens.