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 PancakeRouter02
an 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
You will lose money. Here's why - Since most liquidity pools do not have external oracles to tell them the price ratio between two assets, they rely on participants providing the correct ratio. If you were to, as you say in your example, deposit 1 USDT and 1 ETH into a ETH/USDT pool, you would effectively be stating that you value 1 ETH to be worth 1 USDT. This is obviously not the case, and an external arbitrageur would quickly provide 1 USDT to the pool in exchange for your 1 ETH (Or something close to this, in reality the external arbitrageur would not be able to trade for your full 1 ETH, as the USDT/ETH ratio and therefore price increases asymptotically as the amount of ETH in the pool goes toward 0).
So to answer your question - You'd put in 1 ETH and 1 USDT and a few seconds later you'd be left with a tiny amount of ETH and a couple USDT.
Edit: I initially read your question as starting a pool with this ratio, however the same logic goes if you contribute this ratio to an already existing pool. You wouldn't be lowering the price per ETH to 1 USDT in that pool, but would still be lowering it by some amount inversely proportional to the size of the pool nonetheless and be making some arbitrageur very happy.
Best Answer
Use the below function to know the liquidity of a pair:
If you know the current liquidity and what the pair ratio is, you can deduce the amount of ETH and Token for that pair.