I am trying to make a token sale contract for Ethers. But I have problems with the buy function. I think I have the problem with decimals, but I am not clear about it. I can’t get the equivalence right and it always gives me an error. Where am I going wrong?
I do not know if the price I put is in weis or not. Or even if it should actually divide rather than multiply the price.
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.6.12;
interface TokenInterface {
// determinamos las funciones que necesitamos del ERC20. Tienen que ser iguales.
function decimals() external view returns(uint8);
function balanceOf(address _address) external view returns(uint256);
function transfer(address _to, uint256 _value) external returns (bool success);
}
contract TokenSale {
address owner;
uint256 price;
TokenInterface TokenContract; // Variable de la interface.
uint256 public tokensSold; // Acumulativo de tokens vendidos.
event Sold(address indexed buyer, uint256 amount);
modifier onlyOwner() {
require(msg.sender == owner, "Solo puede llamar el propietario");
_;
}
constructor(uint256 _price, address _addressContract) public {
owner = msg.sender;
price = _price;
// pásamos el contrato del token a nuestra variable interface
TokenContract = TokenInterface(_addressContract);
}
//No importamos toda la libreria SafeMath porque solamente necesitamos la función multiplicación.
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
function priceinWeis() public view returns (uint256) {
return price;
}
function setPrice(uint256 _newprice) public onlyOwner() {
price = _newprice;
}
function etherBalance() public view onlyOwner() returns (uint256) {
return address(this).balance;
}
function tokenBalance() public view onlyOwner() returns (uint256) {
return TokenContract.balanceOf(address(this));
}
function buy(uint256 tokens) public payable {
// que la cantidad que nos paga sea igual al precio x la cantidad de tokens que desea
require(msg.value == mul(price, tokens));
// al llamar la funcion original de transferencia tenemos que indicar la cantidad con los ceros de los decimales.
uint256 amountwithzeros = mul(tokens, uint256(10) ** TokenContract.decimals());
// comprobamos que el contrato de venta tenga los tokens que se desean comprar.
require(TokenContract.balanceOf(address(this)) >= amountwithzeros); //address(this) direccion de nuestro contrato
// realizamos la transferencia con un require por mayor seguridad.
require(TokenContract.transfer(msg.sender, amountwithzeros)); // introducimos la cantidad escalada.
// sumamos la venta.
tokensSold += tokens; // fíjese, que usamos la cantidad sin la suma de los ceros de los decimales.
emit Sold(msg.sender, tokens);
}
// Funcion que liquida el contrato para que no se pueda vender mas.
function endSold() public onlyOwner() {
// compensacion de saldos.
require(TokenContract.transfer(owner, TokenContract.balanceOf(address(this))));
msg.sender.transfer(address(this).balance);
}
}
Expect to transfer toke to the caller successfully, but you should notice that TokenContract should be a standard ERC20 token, that is the function approve in the TokenContract should have a return value.
So if you meet three requirements above, your transaction will succeed.
The price will be in weis. not? If I want to buy 100.000.000 of tokens, for example, it costs 1 ether. not the other way around. It makes no sense to sell tokens more expensive than an ether. This is where I get messed up because the price of a token would have to be the fraction, 0.00000001 not?
Yes, before starting the sale, tokens will be sent to the sale contract by the token contract.
Yes, the contract is a Standard erc20. this is my approve function in the contract:token:
function _approve(address owner, address spender, uint256 amount) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
But, I dont use this function por transfer. I only use this function to addLiquidity
function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
// approve token transfer to cover all possible scenarios
_approve(address(this), address(uniswapV2Router), tokenAmount);
// add the liquidity
uniswapV2Router.addLiquidityETH{value: ethAmount}(
address(this),
tokenAmount,
0, // slippage is unavoidable
0, // slippage is unavoidable
owner(),
block.timestamp
);
}
But if the owner of the token contract and the sale contract is the same, why do I have to approve it? Or is it the address you want to buy that needs to be approved?
I would have to add this instruction before the transfer, right?
Yeah, if it is a standard ERC20 token, the function approve() will have a return value.
And in your showing code addLiquidity(), I think it will call transferFrom(). If you want to add liquidity by this contract, so there should be another function to do aprove, such as
function YOUR_APPROVE() public {
token.aprove(router_address, amount);
}
so once you call this function YOUR_APPROVE(), your contract has approve the router contract, so now you can call the function to add liquidity.
On Sunday I managed to make the first test sale !! But I have to understand well everything that you point out to me here. But now I have another problem and I can't work on remix ... ... until I fix it, I won't be able to move on.
He deployed a few for testing. Now I am testing that the purchase is automatically calculated based on the paid weis. That there is a purchase limit for one ether. Yesterday’s tests didn’t work for me. I will display the contracts today so you can observe it … in the meantime, I will show you the purchase function if you already see a problem in its design.
function buy() public payable {
require( mul(msg.value, price) <= 1000000000000000000);
// calculo de los tokens que se van a mandar.
uint256 tokens = mul(msg.value, price);
// al llamar la funcion original de transferencia tenemos que indicar la cantidad con los ceros de los decimales.
uint256 amountwithzeros = mul(tokens, uint256(10) ** TokenContract.decimals());
// comprobamos que el contrato de venta tenga los tokens que se desean comprar.
require(TokenContract.balanceOf(address(this)) >= amountwithzeros); //address(this) direccion de nuestro contrato
// realizamos la transferencia con un require por mayor seguridad.
require(TokenContract.transfer(msg.sender, amountwithzeros)); // introducimos la cantidad escalada.
// sumamos la venta.
tokensSold += tokens; // fíjese, que usamos la cantidad sin la suma de los ceros de los decimales.
emit Sold(msg.sender, tokens);
}