1

I am using openZeppelin for creating the ICO contract. Could you please help me to understand the below behaviour ?

Crowdsale

The CrowdSale contract is having the function buyTokens(). It calls the _processPurchase(). The _processPurchase() is calling _deliverTokens()

MintedCrowdsale

The MintedCrowdsale contract is also having the function _deliverTokens()

Question : When I call buyTokens() from CrowdSale contract it call the _processPurchase() and processPurchase() is calling _deliverTokens() from MintedCrowdsale Contract and not from CrowdSale contract.. Could you please let me know the reason.

SampleCrowdsale

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

}

Crowdsale

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

MintedCrowdsale

/**
* @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));
}
}

FinalizableCrowdsale

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 {
}
}
  • On which contract address, you are sending ether to trigger fallback. If it is Crowdsale, it should call the function of Mintable. Also how can say that function is getting called from Mintable crowdsale. Please add more clarification. – Aniket Nov 27 '18 at 7:04
0

This is all due to contract inheritance.

If you deployed only the Crowdsale contract and no other contracts and called the buyTokens function, it would of course only execute functionality inside that contract.

But when you have an inheritance hierarchy like yours, you can think of all of the functions getting "combined" or "flattened" into a single contract. When you are calling MintedCrowdsale's function buyTokens, the function comes from the "lowest" possible place in the inheritance hierarchy - in this case it's Crowdsale. That function calls _processPurchase which is also only found in Crowdsale so that one is used.

But when the execution reaches _deliverTokens function call, a lower-level implementation is found in MintedCrowdsale and that one gets called.

Depending on needs, often also the higher-level function needs to be called and that is achieved by calling the super special function in the lower-level function. You can read more about it for example here: (also includes more explanations about inheritance): What does the keyword `super` in Solidity do?

  • ok since super() is not there in _deliverTokens from MintedCrowdsale the control will never reach _deliverTokens in Crowdsale .. correct ? – iappmaker Nov 27 '18 at 7:09
  • Yes, that is correct – Lauri Peltonen Nov 27 '18 at 7:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.