Solidity

在 OpenZeppelin 中,來自 CrowdSale 合約的 _deliverTokens() 未被呼叫

  • November 27, 2018

我正在使用 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 有什麼作用?

引用自:https://ethereum.stackexchange.com/questions/63100