【问题标题】:Problems when buying tokens from a contract using BNB使用 BNB 从合约中购买代币时的问题
【发布时间】:2021-07-29 19:11:31
【问题描述】:

我正在创建这个智能合约,它会创建所有代币并将其添加到我的钱包中。 然后我将钱包中的所有代币发送到我的合约中。

但是,当我从另一个钱包为合约发送 BNB 时,我希望他返还我合约中的一些代币。

当我这样做时,传输失败并发送以下错误消息:

警告!合约执行过程中遇到错误[out of gas]

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

交易详情:https://testnet.bscscan.com/tx/0x7ef36e49e3c6f77716aee79cefbde6c298c3ddeef16ed12dbe613573661135bb

智能合约:

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);
}

}

【问题讨论】:

    标签: blockchain solidity smartcontracts remix


    【解决方案1】:

    根据 BscScan 上的交易详情,您正在尝试发送 0.1 BNB 并且没有调用任何函数。

    你的合约没有receive(),也没有fallback()函数,可以接受传入的BNB。

    所以您需要做的就是实现receive() 函数。请注意允许此函数接受 BNB 的 payable 修饰符。

    contract ERC20Basic is IERC20 {
        // rest of your code
    
        receive() external payable {
            // can call the buy() function
            buy();
        }
    }
    

    您可以在screenshot 中看到,当您向合约发送 100 wei(或在 BNB 的情况下为 100 jager)时,receive() 函数会执行 buy() 函数并生成 Bought 事件日志。

    这是在您的合约上实现的全部代码:

    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();
        }
    
    }
    

    【讨论】:

    • 我的回答中的 sn-p 对您在将 BNB 发送到合同时出现的错误的原始问题作出反应。它允许您将 BNB 发送到合约,因此您(或任何用户)可以稍后调用 sell() 函数,并且合约现在有 BNB 可以发送回用户。它不返回任何代币...如果您想购买代币,您需要直接调用buy() 函数或从receive() 函数中调用。
    • @EvertonFigueiredo 我更新了我的答案,例如从receive() 中调用buy() 函数......你能具体说明“不起作用”是什么意思吗?我能够在 Remix 中成功发送 ETH(对于 BNB 应该是相同的)并且没有遇到任何问题:1)在你的 ERC20Basic 中注释掉 ApprovalTransfer 事件的重新定义(它们已经被定义)在IERC20) 并部署DEX。 2) DEX 的部署给了我的部署地址100 * 10 ** 18 代币。 3)然后我从同一个(部署者)地址向合约发送了 100 wei,并收到了 100 个代币。
    • @EvertonFigueiredo 我用代码更新了答案。使用 Solidity 0.8.1 编译
    • 我在 ERC20Basic 中将 buy () 放在 receive () 上。这一定是错误。
    • 这是有道理的。用户在发送交易时正在与DEX 合约交互 - 而不是与ERC20Basic 交互。所以DEX合约需要实现recieve()函数。很高兴它现在可以工作了。
    猜你喜欢
    • 2018-09-12
    • 2022-01-24
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 2021-07-20
    • 1970-01-01
    • 2020-01-31
    相关资源
    最近更新 更多