2

I am creating this smart contract, it creates and adds all tokens to my wallet. Then I send all the tokens in my wallet to my contract.

However, when from another wallet I send BNB for the contract I wanted him to return a number of tokens that are with my contract.

When I do this the transfer fails and sends the following error message:

Warning! Error encountered during contract execution [out of gas]

Queria saber se estou fazendo algo errado, ou como devo fazer para que meu contrato tenha gas.

Transaction Details: https://testnet.bscscan.com/tx/0x7ef36e49e3c6f77716aee79cefbde6c298c3ddeef16ed12dbe613573661135bb

Smart Contract:

pragma solidity ^0.8.0;

interface IERC20 {

function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);

function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);


event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value); }


contract ERC20Basic is IERC20 {

string public constant name = "ByeSeel";
string public constant symbol = "BYS";
uint8 public constant decimals = 18;


event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
event Transfer(address indexed from, address indexed to, uint tokens);


mapping(address => uint256) balances;

mapping(address => mapping (address => uint256)) allowed;

uint256 totalSupply_ = 100 * 10 ** 18;

using SafeMath for uint256;

constructor() public {
balances[msg.sender] = totalSupply_;
}

function totalSupply() public override view returns (uint256) {
return totalSupply_;
}

function balanceOf(address tokenOwner) public override view returns (uint256) {
    return balances[tokenOwner];
}

function transfer(address receiver, uint256 numTokens) public override returns (bool) {
    require(numTokens <= balances[msg.sender]);
    balances[msg.sender] = balances[msg.sender].sub(numTokens);
    balances[receiver] = balances[receiver].add(numTokens);
    emit Transfer(msg.sender, receiver, numTokens);
    return true;
}

function approve(address delegate, uint256 numTokens) public override returns (bool) {
    allowed[msg.sender][delegate] = numTokens;
    emit Approval(msg.sender, delegate, numTokens);
    return true;
}

function allowance(address owner, address delegate) public override view returns (uint) {
    return allowed[owner][delegate];
}

function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
    require(numTokens <= balances[owner]);
    require(numTokens <= allowed[owner][msg.sender]);

    balances[owner] = balances[owner].sub(numTokens);
    allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
    balances[buyer] = balances[buyer].add(numTokens);
    emit Transfer(owner, buyer, numTokens);
    return true;
}

event Received(address, uint);
 receive() external payable {
 emit Received(msg.sender, msg.value);
}

 }

library SafeMath {
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
  assert(b <= a);
  return a - b;
}

function add(uint256 a, uint256 b) internal pure returns (uint256) {
  uint256 c = a + b;
  assert(c >= a);
  return c;
} }

contract DEX {

event Bought(uint256 amount);
event Sold(uint256 amount);


IERC20 public token;

constructor() public {
    token = new ERC20Basic();
}

function buy() payable public {
    uint256 amountTobuy = msg.value;
    uint256 dexBalance = token.balanceOf(address(this));
    require(amountTobuy > 0, "You need to send some Ether");
    require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
    token.transfer(msg.sender, amountTobuy);
    emit Bought(amountTobuy);
}

function sell(uint256 amount) public {
    require(amount > 0, "You need to sell at least some tokens");
    uint256 allowance = token.allowance(msg.sender, address(this));
    require(allowance >= amount, "Check the token allowance");
    token.transferFrom(msg.sender, address(this), amount);
    msg.sender.transfer(amount);
    emit Sold(amount);
}

}

1 Answers1

2

According to the transaction detail on BscScan, you're trying to send 0.1 BNB and not calling any function.

Your contract does not have the receive(), nor the fallback() function, that would accept the incoming BNB.

So all you need to do is implement the receive() function. Mind the payable modifier that allows this function to accept BNB.

contract ERC20Basic is IERC20 {
    // rest of your code

    receive() external payable {
        // can call the buy() function
        buy();
    }
}

You can see in the screenshot that when you send 100 wei (or 100 jager in case of BNB) to the contract, the receive() function executes the buy() function and produces the Bought event log.

Here's the whole code implemented on your contract:

pragma solidity ^0.8.0;

interface IERC20 {

function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);

function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);


event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
    
}


contract ERC20Basic is IERC20 {

string public constant name = "ByeSeel";
string public constant symbol = "BYS";
uint8 public constant decimals = 18;


//event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
//event Transfer(address indexed from, address indexed to, uint tokens);


mapping(address => uint256) balances;

mapping(address => mapping (address => uint256)) allowed;

uint256 totalSupply_ = 100 * 10 ** 18;

using SafeMath for uint256;

constructor() public {
balances[msg.sender] = totalSupply_;
}

function totalSupply() public override view returns (uint256) {
return totalSupply_;
}

function balanceOf(address tokenOwner) public override view returns (uint256) {
    return balances[tokenOwner];
}

function transfer(address receiver, uint256 numTokens) public override returns (bool) {
    require(numTokens <= balances[msg.sender]);
    balances[msg.sender] = balances[msg.sender].sub(numTokens);
    balances[receiver] = balances[receiver].add(numTokens);
    emit Transfer(msg.sender, receiver, numTokens);
    return true;
}

function approve(address delegate, uint256 numTokens) public override returns (bool) {
    allowed[msg.sender][delegate] = numTokens;
    emit Approval(msg.sender, delegate, numTokens);
    return true;
}

function allowance(address owner, address delegate) public override view returns (uint) {
    return allowed[owner][delegate];
}

function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
    require(numTokens <= balances[owner]);
    require(numTokens <= allowed[owner][msg.sender]);

    balances[owner] = balances[owner].sub(numTokens);
    allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
    balances[buyer] = balances[buyer].add(numTokens);
    emit Transfer(owner, buyer, numTokens);
    return true;
}

event Received(address, uint);
 receive() external payable {
 emit Received(msg.sender, msg.value);
}

 }

library SafeMath {
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
  assert(b <= a);
  return a - b;
}

function add(uint256 a, uint256 b) internal pure returns (uint256) {
  uint256 c = a + b;
  assert(c >= a);
  return c;
} }

contract DEX {

    event Bought(uint256 amount);
    event Sold(uint256 amount);
    
    
    IERC20 public token;
    
    constructor() public {
        token = new ERC20Basic();
    }
    
    function buy() payable public {
        uint256 amountTobuy = msg.value;
        uint256 dexBalance = token.balanceOf(address(this));
        require(amountTobuy > 0, "You need to send some Ether");
        require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
        token.transfer(msg.sender, amountTobuy);
        emit Bought(amountTobuy);
    }
    
    function sell(uint256 amount) public {
        require(amount > 0, "You need to sell at least some tokens");
        uint256 allowance = token.allowance(msg.sender, address(this));
        require(allowance >= amount, "Check the token allowance");
        token.transferFrom(msg.sender, address(this), amount);
        payable(msg.sender).transfer(amount);
        emit Sold(amount);
    }
    
    receive() external payable {
        buy();
    }

}
Petr Hejda
  • 40,554
  • 8
  • 72
  • 100
  • Find the code you spoke about, I modified the question with the update. I was able to successfully send BNB to the contract, but he did not return my token to me, do I need to implement fallback ()? Could you give me an example? – Everton Figueiredo May 07 '21 at 13:39
  • 1
    The snippet in my answer reacts to your original question about the error when you're sending BNB to a contract. It allows you to send BNB to the contract, so you (or any user) can later call the `sell()` function and the contract has now BNB to send back to the user. It doesn't return any tokens... If you want to buy tokens, you need to call the `buy()` function directly or from within the `receive()` function. – Petr Hejda May 07 '21 at 14:02
  • 1
    @EvertonFigueiredo I updated my answer with example of calling the `buy()` function from within the `receive()` ... Can you specify what do you mean by "doesn't work"? I was able to successfully send ETH (should be same for BNB) in Remix and didn't run into any issue: 1) Commented out the redefinition of `Approval` and `Transfer` events in your `ERC20Basic` (they are already defined in the `IERC20`) and deployed `DEX`. 2) The deployment of DEX gave `100 * 10 ** 18` tokens to my deployer address. 3) Then I sent 100 wei to the contract from the same (deployer) address and received 100 tokens. – Petr Hejda May 07 '21 at 14:32
  • Incredible as it seems mine can't call the buy that way, could you send me the whole code so I can see how you are doing? – Everton Figueiredo May 07 '21 at 14:43
  • 1
    @EvertonFigueiredo I updated the answer with the code. Compiled with Solidity 0.8.1 – Petr Hejda May 07 '21 at 14:46
  • 1
    I was putting buy () on receive () from within ERC20Basic. This must have been the error. – Everton Figueiredo May 07 '21 at 14:47
  • 1
    That makes sense. The user is interacting with the `DEX` contract - not with the `ERC20Basic` when they are sending a transaction. So the `DEX` contract needs to implement the `recieve()` function. Glad it works now. – Petr Hejda May 07 '21 at 14:49
  • https://testnet.bscscan.com/address/0x86ceb61baf69729db13a2e7208d48bbc1dca8d01 Now it is receiving but it is not returning the tokens. – Everton Figueiredo May 07 '21 at 14:56
  • 1
    @EvertonFigueiredo Please verify the contract on BscScan. There's probably something done differently and it's very hard to debug without seeing the source code. – Petr Hejda May 07 '21 at 15:17
  • The contract I'm selecting to compile in Remix is ​​ERC20Basic, but in this case the Buy () function is in the DEX contract, isn't that why it's not working? I believe that I am not doing the compilation the right way. https://testnet.bscscan.com/address/0xa18fb95f7501a447dfe97c91eeb2eb5692fc9e22#code – Everton Figueiredo May 07 '21 at 15:49
  • 1
    @EvertonFigueiredo You need to compile the DEX contract - not the ERC20Basic. See my second comment here. – Petr Hejda May 07 '21 at 16:11
  • But if I don't compile the ERC20Basic how will I generate the tokens? – Everton Figueiredo May 07 '21 at 16:54
  • 1
    The ERC20Basic gets compiled as well, because it's used by the `token` property in DEX. But the main contract needs to be the `DEX`. – Petr Hejda May 07 '21 at 17:30
  • https://testnet.bscscan.com/token/0xb570E6Fff85CBE695c9394bDa7d55fb38a009A28 When compiled by DEX the contract is not generated automatically, I cannot even see the name, symbol or total of currencies. – Everton Figueiredo May 07 '21 at 17:36
  • 1
    @EvertonFigueiredo That's a separate issue. Please open a new question so that we don't spam the comments, show what you've tried so far, produce a reproducible example, etc. – Petr Hejda May 07 '21 at 17:37
  • https://stackoverflow.com/questions/67439700/token-information-does-not-show-when-compiled – Everton Figueiredo May 07 '21 at 17:58