4

I've seen some scams that :

  1. In deploy stage all tokens goes to the owner.
  2. The owner go to PancakeSwap and create a liquidity pool using some BNB he have and all supply of tokens.
  3. After some time the owner pulls the rug and clean the LP.

I need to create a more transparent and reliable token and then I think I could allow the own contract to receive some BNB (an ICO maybe?) and then decides when to create the liquidity pool.

So after renounce the contract it cannot be any way to pull back the LP. It could give the investors some peace.

I can see any cheap way to lock the LP.... it can be a solution to this question too.

So my question is: how can I use solidity to create (inside the contract) a new Liquidity Pool just the way I would create using PancakeSwap ?

Some MootRat clones have this code:

    function addLiquidity(
        address routerAddress,
        address owner,
        uint256 tokenAmount,
        uint256 ethAmount
    ) public {
        IPancakeRouter02 pancakeRouter = IPancakeRouter02(routerAddress);

        // add the liquidity
        pancakeRouter.addLiquidityETH{value : ethAmount}(
            address(this),
            tokenAmount,
            0, // slippage is unavoidable
            0, // slippage is unavoidable
            owner,
            block.timestamp + 360
        );
    }

But I think it is missing something...

2
+50

Since the you (the contract) are adding ETH/Token as liquidity, your function needs to be marked as internal/private. Additionally, you need to give the PancakeRouter02an allowance to spend at least tokenAmount of the token.

Here's a contract that mints initialSupply tokens, then adds tokenAmount/msg.value as liquidity.

PS: I haven't tested it


import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./../interfaces/IUniswapV2Router.sol";


contract Test is ERC20, Ownable {

    address constant routerAddress = 0x10ED43C718714eb63d5aA57B78B54704E256024E;

    constructor(uint initialSupply, uint tokenAmount) ERC20("Test", "TST") public payable {
        _mint(address(this), initialSupply);
        approve(routerAddress, tokenAmount);
        addLiquidity(address(this), tokenAmount);

        // Do your burn here / renounce ownership
    }

    function addLiquidity(
        address owner,
        uint256 tokenAmount
    ) internal {

        IUniswapV2Router02 pancakeRouter = IUniswapV2Router02(routerAddress);
        // add the liquidity
        pancakeRouter.addLiquidityETH{value: msg.value}(
            address(this),
            tokenAmount,
            0, // slippage is unavoidable
            0, // slippage is unavoidable
            owner,
            block.timestamp + 360
        );
    }

}

Source: https://uniswap.org/docs/v2/smart-contracts/router02/#addliquidityeth

EDIT: Decided to test if this would work - it fails on the addLiquidity function. I assume this is because the Token's methods like _transfer and approve don't actually exist outside of the contract itself. That is, the UniswapV2Factory doesn't know anything about the token yet (except the address being passed) - there is no code deployed there yet.

If you want to add liquidity in one transaction, you can instead do something like this using a Factory pattern

contract Factory {
    
    Token public token;

    constructor(string memory name, string memory symbol, address router) public payable {

        token = new Token(name, symbol, router);

        (,,uint256 liquidity) = IUniswapV2Router02(router).addLiquidityETH{value: msg.value}(
            address(token),
            token.totalSupply(),
            0, 
            0, 
            address(this), 
            block.timestamp
        );

        // Renounce ownership + burn liquidity here

    }
}

In the constructor of Token, you can do your approval and minting. E.g. Mint tokens to the Factory and give the Factory an approval to the router using the internal function _approve

3
  • Great!! I'll test and then pay your bounty
    – Magno C
    Jun 24 at 2:46
  • And +1 for using the clean and easy OpenZeppelin
    – Magno C
    Jun 24 at 2:48
  • about your edit I think the constructor is not the best place to put this. This is because the fail you found and because the contract has no money yet to pair with its tokens. So I think we have to start some ICO ( allow receive ) to store some BNB and then create the LP.
    – Magno C
    Aug 21 at 1:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.