Solidity
在 OpenZeppelin 中,來自 CrowdSale 合約的 _deliverTokens() 未被呼叫
我正在使用 openZeppelin 創建 ICO 合約。您能幫我理解以下行為嗎?
眾籌
CrowdSale 合約具有功能
buyTokens()
。它呼叫_processPurchase()
. 正在_processPurchase()
打電話_deliverTokens()
鑄幣眾籌
MintedCrowdsale 合約也有這個功能
_deliverTokens()
問題: 當我
buyTokens()
從 CrowdSale 合約呼叫時,它呼叫_processPurchase()
andprocessPurchase()
是_deliverTokens()
從MintedCrowdsale
合約呼叫而不是從CrowdSale
合約呼叫。請告訴我原因。樣品眾籌
contract SampleCrowdsale is FinalizableCrowdsale, MintedCrowdsale { event CrowdsaleFinalized(); constructor( uint256 openingTime, uint256 closingTime, uint256 rate, address wallet, address secWallet, ERC20Mintable token ) public Crowdsale(rate, wallet,secWallet, token) TimedCrowdsale(openingTime, closingTime) { } }
眾籌
contract Crowdsale is ReentrancyGuard { using SafeMath for uint256; using SafeERC20 for IERC20; // The token being sold IERC20 private _token; // Address where funds are collected address private _wallet; // Address where sec % funds are collected address private _secWallet; // How many token units a buyer gets per wei. // The rate is the conversion between wei and the smallest and indivisible token unit. // So, if you are using a rate of 1 with a ERC20Detailed token with 3 decimals called TOK // 1 wei will give you 1 unit, or 0.001 TOK. uint256 private _rate; // Amount of wei raised uint256 private _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 TokensPurchased( address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount ); /** * @param rate Number of token units a buyer gets per wei * @dev The rate is the conversion between wei and the smallest and indivisible * token unit. So, if you are using a rate of 1 with a ERC20Detailed token * with 3 decimals called TOK, 1 wei will give you 1 unit, or 0.001 TOK. * @param wallet Address where collected funds will be forwarded to * @param token Address of the token being sold */ constructor(uint256 rate, address wallet,address secWallet, IERC20 token) internal { require(rate > 0); require(wallet != address(0)); require(token != address(0)); _rate = rate; _wallet = wallet; _secWallet=secWallet; _token = token; } // ----------------------------------------- // Crowdsale external interface // ----------------------------------------- /** * @dev fallback function ***DO NOT OVERRIDE*** * Note that other contracts will transfer fund with a base gas stipend * of 2300, which is not enough to call buyTokens. Consider calling * buyTokens directly when purchasing tokens from a contract. */ function () external payable { buyTokens(msg.sender); } /** * @return the token being sold. */ function token() public view returns(IERC20) { return _token; } /** * @return the address where funds are collected. */ function wallet() public view returns(address) { return _wallet; } /** * @return the number of token units a buyer gets per wei. */ function rate() public view returns(uint256) { return _rate; } /** * @return the amount of wei raised. */ function weiRaised() public view returns (uint256) { return _weiRaised; } /** * @dev low level token purchase ***DO NOT OVERRIDE*** * This function has a non-reentrancy guard, so it shouldn't be called by * another `nonReentrant` function. * @param beneficiary Recipient of the token purchase */ function buyTokens(address beneficiary) public nonReentrant 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 TokensPurchased( msg.sender, beneficiary, weiAmount, tokens ); _updatePurchasingState(beneficiary, weiAmount); _forwardFunds(); _postValidatePurchase(beneficiary, weiAmount); } // ----------------------------------------- // Internal interface (extensible) // ----------------------------------------- /** * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use `super` in contracts that inherit from Crowdsale to extend their validations. * Example from CappedCrowdsale.sol's _preValidatePurchase method: * super._preValidatePurchase(beneficiary, weiAmount); * require(weiRaised().add(weiAmount) <= cap); * @param beneficiary Address performing the token purchase * @param weiAmount Value in wei involved in the purchase */ function _preValidatePurchase( address beneficiary, uint256 weiAmount ) internal view { 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 view { // optional override } /** * @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.safeTransfer(beneficiary, tokenAmount); } /** * @dev Executed when a purchase has been validated and is ready to be executed. Doesn't necessarily emit/send 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 { uint256 firstAmt = msg.value.mul(9); uint256 secAmt; firstAmt=firstAmt.div(100); _wallet.transfer(firstAmt); secAmt=msg.value.sub(firstAmt); _secWallet.transfer(secAmt); } }
鑄幣眾籌
/** * @title MintedCrowdsale * @dev Extension of Crowdsale contract whose tokens are minted in each purchase. * Token ownership should be transferred to MintedCrowdsale for minting. */ contract MintedCrowdsale is Crowdsale { constructor() internal {} /** * @dev Overrides delivery by minting tokens upon purchase. * @param beneficiary Token purchaser * @param tokenAmount Number of tokens to be minted */ function _deliverTokens( address beneficiary, uint256 tokenAmount ) internal { // Potentially dangerous assumption about the type of the token. require( ERC20Mintable(address(token())).mint(beneficiary, tokenAmount)); } }
可定案的眾售
contract FinalizableCrowdsale is TimedCrowdsale { using SafeMath for uint256; bool private _finalized; event CrowdsaleFinalized(); constructor() internal { _finalized = false; } /** * @return true if the crowdsale is finalized, false otherwise. */ function finalized() public view returns (bool) { return _finalized; } /** * @dev Must be called after crowdsale ends, to do some extra finalization * work. Calls the contract's finalization function. */ function finalize() public { require(!_finalized); require(hasClosed()); _finalized = true; _finalization(); emit CrowdsaleFinalized(); } /** * @dev Can be overridden to add finalization logic. The overriding function * should call super._finalization() to ensure the chain of finalization is * executed entirely. */ function _finalization() internal { } }
這都是由於契約繼承。
如果您只部署
Crowdsale
合約而不部署其他合約並呼叫該buyTokens
函式,它當然只會執行該合約內部的功能。但是當你有一個像你這樣的繼承層次結構時,你可以認為所有的功能都被“組合”或“扁平化”到一個單一的契約中。當您呼叫
MintedCrowdsale
’s functionbuyTokens
時,該函式來自繼承層次結構中可能的“最低”位置 - 在本例中為Crowdsale
. 該函式呼叫_processPurchase
也只能在其中找到,Crowdsale
以便使用。但是當執行到達
_deliverTokens
函式呼叫時,會在其中找到一個較低級別的實現並呼叫該實現MintedCrowdsale
。根據需要,通常還需要呼叫更高級別的函式,這是通過呼叫
super
較低級別函式中的特殊函式來實現的。例如,您可以在此處閱讀更多相關資訊:(還包括有關繼承的更多解釋):Solidity 中的關鍵字super
有什麼作用?