ICO,转移资金

ICO, transfering funds

提问人:Santos 提问时间:8/11/2023 最后编辑:Santos 更新时间:8/15/2023 访问量:75

问:

我正在创建一个简单的 ICO 合约,它会在合约收到以太币后立即将购买的代币数量发送给买方,然后将收到的以太币发送到不同的钱包,我整天都在 remix 上测试它,但是,合约收到以太币但不将以太币发送到钱包,买家也没有收到她的。这是购买功能。

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "./SafeMath.sol";


interface IERC20 {
    function totalSupply() external view returns (uint);

    function balanceOf(address account) external view returns (uint);

    function transfer(address recipient, uint amount) external returns (bool);

    function allowance(
        address owner,
        address spender
    ) external view returns (uint);

    function approve(address spender, uint amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);

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

    function burn(uint256 _value) external returns (bool success);
}

contract Crowdsale {
    using SafeMath for uint256;

    // The token being sold
    IERC20 public token;

    // Address where funds are collected
    IERC20 public wallet;

    // How many token units a buyer gets per wei
    uint256 public rate;

    // Amount of wei raised
    uint256 public weiRaised;

    /**
     * Event for token purchase logging
     * @param purchaser who paid for the tokens
     * @param beneficiary who got the tokens
     * @param value weis paid for purchase
     * @param amount amount of tokens purchased
     */
    event TokenPurchase(
        address indexed purchaser,
        address indexed beneficiary,
        uint256 value,
        uint256 amount
    );

    /**
     * @param _rate Number of token units a buyer gets per wei
     * @param _wallet Address where collected funds will be forwarded to
     * @param _token Address of the token being sold
     */

    constructor(uint256 _rate, address _wallet, address _token) {
        require(_rate > 0);
        require(_wallet != address(0));
        require(_token != address(0));

        rate = _rate;
        wallet = IERC20(_wallet);
        token = IERC20(_token);
    }

    /**
   * @dev fallback function ***DO NOT OVERRIDE***
  //  */
    fallback() external payable {
        buyTokens(msg.sender);
    }

    // receive() external payable{}

    /**
     * @dev low level token purchase ***DO NOT OVERRIDE***
     * @param _beneficiary Address performing the token purchase
     */
    function buyTokens(address _beneficiary) public payable {
        uint256 weiAmount = msg.value;
        _preValidatePurchase(_beneficiary, weiAmount);

        // calculate token amount to be created
        uint256 tokens = _getTokenAmount(weiAmount);

        // update state
        weiRaised = weiRaised.add(weiAmount);
        _processPurchase(_beneficiary, tokens);

        emit TokenPurchase(msg.sender, _beneficiary, weiAmount, tokens);

        _updatePurchasingState(_beneficiary, weiAmount);
        _forwardFunds();
        _postValidatePurchase(_beneficiary, weiAmount);
    }

    /**
     * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use super to concatenate validations.
     * @param _beneficiary Address performing the token purchase
     * @param _weiAmount Value in wei involved in the purchase
     */
    function _preValidatePurchase(
        address _beneficiary,
        uint256 _weiAmount
    ) internal pure {
        require(_beneficiary != address(0));
        require(_weiAmount != 0);
    }

    /**
     * @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid conditions are not met.
     * @param _beneficiary Address performing the token purchase
     * @param _weiAmount Value in wei involved in the purchase
     */
    function _postValidatePurchase(
        address _beneficiary,
        uint256 _weiAmount
    ) internal {
        // optional override
    }

    // 0x4815A8Ba613a3eB21A920739dE4cA7C439c7e1b1
    // 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db
    /**
     * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
     * @param _beneficiary Address performing the token purchase
     * @param _tokenAmount Number of tokens to be emitted
     */
    function _deliverTokens(
        address _beneficiary,
        uint256 _tokenAmount
    ) internal {
        token.transfer(_beneficiary, _tokenAmount);
    }

    /**
     * @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
     * @param _beneficiary Address receiving the tokens
     * @param _tokenAmount Number of tokens to be purchased
     */
    function _processPurchase(
        address _beneficiary,
        uint256 _tokenAmount
    ) internal {
        _deliverTokens(_beneficiary, _tokenAmount);
    }

    /**
     * @dev Override for extensions that require an internal state to check for validity (current user contributions, etc.)
     * @param _beneficiary Address receiving the tokens
     * @param _weiAmount Value in wei involved in the purchase
     */
    function _updatePurchasingState(
        address _beneficiary,
        uint256 _weiAmount
    ) internal {
        // optional override
    }

    /**
     * @dev Override to extend the way in which ether is converted to tokens.
     * @param _weiAmount Value in wei to be converted into tokens
     * @return Number of tokens that can be purchased with the specified _weiAmount
     */
    function _getTokenAmount(
        uint256 _weiAmount
    ) internal view returns (uint256) {
        return _weiAmount.mul(rate);
    }

    /**
     * @dev Determines how ETH is stored/forwarded on purchases.
     */
    function _forwardFunds() internal {
        // bool sent =  wallet.transfer(address(wallet),msg.value);
        wallet.transfer(address(wallet), msg.value);
        // require(sent, "Transaction failed");
    }

    function getWallet() public view returns (uint) {
        return address(wallet).balance;
    }

    function getTokenBalance() public view returns (uint) {
        return address(token).balance;
    }
}

Solidity Web3JS Ethers.js Remix ICO

评论

0赞 Alon Ben Yaakov 8/11/2023
您能否用完整的合同代码更新问题?
0赞 Santos 8/12/2023
是的,我已经做到了。

答:

0赞 Alon Ben Yaakov 8/12/2023 #1

我们需要首先就您的目标达成一致:

任何人都可以使用链的原生代币以您预定义的汇率购买您的代币。一旦有人成功购买了代币,那么 msg.value 中可访问的原生代币数量将被转发到您预定义的钱包。

此外,关于您的合约是如何构建的,您似乎计划将 ERC20 代币与众筹合约分开部署。如果没有,请在下面评论您希望众筹也部署 ERC20 代币。

在就目标达成一致后,需要使用当前代码进行多次修复才能实现它。

一、ERC20代币的部署顺序和供应情况:

  1. 部署 ERC20 合约 - 需要合约地址才能部署众筹合约(地址_token)
  2. 部署此众筹合约
  3. 将您要在此ICO上出售的代币数量转移到 众筹。

其次,我们需要修复您的合同的一部分,以便转发买家用于购买您的代币的原生代币:

  1. 目前,您将目标钱包的类型设置为 IERC20,这是不正确的。因为你想转移链的原生币,所以你需要将变量的类型设置为地址,因为你只是保存了目标钱包地址,而不是合约。
    // Address where funds are collected
    address public wallet;
  1. 在 _forwardFunds 函数中,您要转移 ETH 而不是 ERC20 代币,因此该函数应如下所示:
    /**
     * @dev Determines how ETH is stored/forwarded on purchases.
     */
    function _forwardFunds(uint256 _value) internal {
        // bool sent =  wallet.transfer(address(wallet),msg.value);
   address payable receiver = payable(wallet);
   receiver.transfer(_value);
        // require(sent, "Transaction failed");
    }

  1. 您还应该添加接收函数,以便能够接受链的原生货币,并使其也能正确显示在区块浏览器上。接收和回退之间的区别
    //Required to be able to accept native currency of the network(ETH)
    event Received(address, uint256);

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

完整代码:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "./SafeMath.sol";


interface IERC20 {
    function totalSupply() external view returns (uint);

    function balanceOf(address account) external view returns (uint);

    function transfer(address recipient, uint amount) external returns (bool);

    function allowance(
        address owner,
        address spender
    ) external view returns (uint);

    function approve(address spender, uint amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);

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

    function burn(uint256 _value) external returns (bool success);
}

contract Crowdsale {
    using SafeMath for uint256;

    // The token being sold
    IERC20 public token;

    // Address where funds are collected
    address public wallet;

    // How many token units a buyer gets per wei
    uint256 public rate;

    // Amount of wei raised
    uint256 public weiRaised;

    /**
     * Event for token purchase logging
     * @param purchaser who paid for the tokens
     * @param beneficiary who got the tokens
     * @param value weis paid for purchase
     * @param amount amount of tokens purchased
     */
    event TokenPurchase(
        address indexed purchaser,
        address indexed beneficiary,
        uint256 value,
        uint256 amount
    );

    /**
     * @param _rate Number of token units a buyer gets per wei
     * @param _wallet Address where collected funds will be forwarded to
     * @param _token Address of the token being sold
     */

    constructor(uint256 _rate, address _wallet, address _token) {
        require(_rate > 0);
        require(_wallet != address(0));
        require(_token != address(0));

        rate = _rate;
        wallet = _wallet;
        token = IERC20(_token);
    }

    /**
   * @dev fallback function ***DO NOT OVERRIDE***
  //  */
    fallback() external payable {
        buyTokens(msg.sender);
    }

    //Required to be able to accept native currency of the network(ETH)
    event Received(address, uint256);

    receive() external payable {
        emit Received(msg.sender, msg.value);
        buyTokens(msg.sender);
    }

    /**
     * @dev low level token purchase ***DO NOT OVERRIDE***
     * @param _beneficiary Address performing the token purchase
     */
    function buyTokens(address _beneficiary) public payable {
        uint256 weiAmount = msg.value;
        _preValidatePurchase(_beneficiary, weiAmount);

        // calculate token amount to be created
        uint256 tokens = _getTokenAmount(weiAmount);

        // update state
        weiRaised = weiRaised.add(weiAmount);
        _processPurchase(_beneficiary, tokens);

        emit TokenPurchase(msg.sender, _beneficiary, weiAmount, tokens);

        _updatePurchasingState(_beneficiary, weiAmount);
        _forwardFunds();
        _postValidatePurchase(_beneficiary, weiAmount);
    }

    /**
     * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use super to concatenate validations.
     * @param _beneficiary Address performing the token purchase
     * @param _weiAmount Value in wei involved in the purchase
     */
    function _preValidatePurchase(
        address _beneficiary,
        uint256 _weiAmount
    ) internal pure {
        require(_beneficiary != address(0));
        require(_weiAmount != 0);
    }

    /**
     * @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid conditions are not met.
     * @param _beneficiary Address performing the token purchase
     * @param _weiAmount Value in wei involved in the purchase
     */
    function _postValidatePurchase(
        address _beneficiary,
        uint256 _weiAmount
    ) internal {
        // optional override
    }

    // 0x4815A8Ba613a3eB21A920739dE4cA7C439c7e1b1
    // 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db
    /**
     * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
     * @param _beneficiary Address performing the token purchase
     * @param _tokenAmount Number of tokens to be emitted
     */
    function _deliverTokens(
        address _beneficiary,
        uint256 _tokenAmount
    ) internal {
        token.transfer(_beneficiary, _tokenAmount);
    }

    /**
     * @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
     * @param _beneficiary Address receiving the tokens
     * @param _tokenAmount Number of tokens to be purchased
     */
    function _processPurchase(
        address _beneficiary,
        uint256 _tokenAmount
    ) internal {
        _deliverTokens(_beneficiary, _tokenAmount);
    }

    /**
     * @dev Override for extensions that require an internal state to check for validity (current user contributions, etc.)
     * @param _beneficiary Address receiving the tokens
     * @param _weiAmount Value in wei involved in the purchase
     */
    function _updatePurchasingState(
        address _beneficiary,
        uint256 _weiAmount
    ) internal {
        // optional override
    }

    /**
     * @dev Override to extend the way in which ether is converted to tokens.
     * @param _weiAmount Value in wei to be converted into tokens
     * @return Number of tokens that can be purchased with the specified _weiAmount
     */
    function _getTokenAmount(
        uint256 _weiAmount
    ) internal view returns (uint256) {
        return _weiAmount.mul(rate);
    }

    /**
     * @dev Determines how ETH is stored/forwarded on purchases.
     */
    function _forwardFunds() internal {
        // bool sent =  wallet.transfer(address(wallet),msg.value);
   address payable receiver = payable(wallet);
   receiver.transfer(msg.value);
        // require(sent, "Transaction failed");
    }

    function getWalletBalance() public view returns (uint) {
        return address(wallet).balance;
    }

    function getTokenBalance() public view returns (uint) {
        return address(token).balance;
    }

}



附言: 看到你的getWallet公共函数的目的是获取钱包余额,所以我把它重命名为getWalletBalance。

编辑1

我已经成功地从头到尾测试了它。 我使用 Remix 进行部署和合约交互,并将其部署到孟买网络(Polygon 测试网)。交易链接

也许您不小心执行了 buyTokens 函数,而没有实际传递带有请求的原生代币?您需要将值从默认的 0 更改为请求的金额,并附上图像:

Set transaction native coin value

编辑 2

你不需要传递msg.value,它们在交易的生命周期中是持久的(我的错误,我已经删除了关于这一点的部分)

如果你想通过只转移原生币(ETH/MATIC等)来触发购买,你需要在接收和回退函数上触发buyTokens函数。

评论

0赞 Santos 8/12/2023
是的,你是对的,我已经更新了合约,但使用 Remix,我仍然无法将原生代币转移到钱包,并且 ERC20 代币不会转移给买家,可能是没有使用适当的测试网的情况吗?
0赞 Alon Ben Yaakov 8/12/2023
请参阅我添加到解决方案中的编辑部分。此外,我假设您正在按照解决方案开始时提到的部署步骤进行操作。
0赞 Santos 8/12/2023
这些是我的步骤。我创建了一个 ERC 代币,使用了代币合约,并添加了另一个钱包地址和利率作为部署众筹合约的参数。然后我向合约发送了一些代币,然后使用另一个帐户通过将 Eth 发送到众筹地址来购买代币,众筹收到了原生代币,但它没有将其发送到 walletAddress,也没有发送 ERCtoken
0赞 Alon Ben Yaakov 8/13/2023
我添加了一个修复程序(参见 edit2),使其也仅适用于合约中的原生硬币(ETH/MATIC 等)。如果它仍然不适合您,请添加您是否只是将原生币发送到合约或正在触发 buyTokens 函数,并在区块浏览器上添加交易链接。
0赞 Santos 8/13/2023
它仍然不起作用,我还没有在任何测试网上部署它,所有事务都是在混音 VM 上完成的。我一直在使用 Remix 帐户进行测试