提问人:Santos 提问时间:8/11/2023 最后编辑:Santos 更新时间:8/15/2023 访问量:75
ICO,转移资金
ICO, transfering funds
问:
我正在创建一个简单的 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;
}
}
答:
0赞
Alon Ben Yaakov
8/12/2023
#1
我们需要首先就您的目标达成一致:
任何人都可以使用链的原生代币以您预定义的汇率购买您的代币。一旦有人成功购买了代币,那么 msg.value 中可访问的原生代币数量将被转发到您预定义的钱包。
此外,关于您的合约是如何构建的,您似乎计划将 ERC20 代币与众筹合约分开部署。如果没有,请在下面评论您希望众筹也部署 ERC20 代币。
在就目标达成一致后,需要使用当前代码进行多次修复才能实现它。
一、ERC20代币的部署顺序和供应情况:
- 部署 ERC20 合约 - 需要合约地址才能部署众筹合约(地址_token)
- 部署此众筹合约
- 将您要在此ICO上出售的代币数量转移到 众筹。
其次,我们需要修复您的合同的一部分,以便转发买家用于购买您的代币的原生代币:
- 目前,您将目标钱包的类型设置为 IERC20,这是不正确的。因为你想转移链的原生币,所以你需要将变量的类型设置为地址,因为你只是保存了目标钱包地址,而不是合约。
// Address where funds are collected
address public wallet;
- 在 _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");
}
- 您还应该添加接收函数,以便能够接受链的原生货币,并使其也能正确显示在区块浏览器上。接收和回退之间的区别:
//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 更改为请求的金额,并附上图像:
编辑 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 帐户进行测试
评论