I am trying to implement a default cap on every beneficiary that sends ETH to the sale contract. By default i have to set cap manually on each address, which is not usable.
Also i am using CappedCrowdsale to set a cap on whole crowdsale.
I am assuming it has something to do with PreValidatePurchase function? Also how would i add “cap” for individuals in the constructor. Please simplify it a bit as i am still a novice in all this.
If you want to add a default individual cap as well as being able to set a cap on specific individuals then you could extend IndividuallyCappedCrowdsale to:
add a default individual cap state variable and a function to set it
override getCap(address beneficiary) to return the default individual cap if an individual cap isn’t set
override _preValidatePurchase to check if an individaul cap is set, otherwise to use the default individual cap.
The compiler error is because you are changing state in a view function which you cannot do.
When you override _preValidatePurchase you should only check that the contributions are under the cap and not change any state.
It may be easier to duplicate the functionality in IndividuallyCappedCrowdsale due to the logic in _preValidatePurchase as overriding and calling super would call this logic.
You could do something like the following for example.
The following code has not been tested and not been audited. Code used in production should be appropriately tested and audited.
pragma solidity ^0.5.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/crowdsale/validation/PausableCrowdsale.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/crowdsale/validation/CappedCrowdsale.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/crowdsale/emission/MintedCrowdsale.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.5.1/contracts/access/roles/CapperRole.sol";
contract BOTSale is PausableCrowdsale, CappedCrowdsale, MintedCrowdsale, CapperRole {
using SafeMath for uint256;
mapping(address => uint256) private _contributions;
mapping(address => uint256) private _caps;
uint256 private _individualDefaultCap;
constructor (
uint256 rate,
address payable wallet,
IERC20 token,
uint256 cap,
uint256 individualCap
)
public
Crowdsale(rate, wallet, token)
CappedCrowdsale(cap)
{
_individualDefaultCap = individualCap;
}
/**
* @dev Sets a specific beneficiary's maximum contribution.
* @param beneficiary Address to be capped
* @param cap Wei limit for individual contribution
*/
function setCap(address beneficiary, uint256 cap) external onlyCapper {
_caps[beneficiary] = cap;
}
/**
* @dev Returns the cap of a specific beneficiary.
* @param beneficiary Address whose cap is to be checked
* @return Current cap for individual beneficiary
*/
function getCap(address beneficiary) public view returns (uint256) {
uint256 cap = _caps[beneficiary];
if (cap == 0) {
cap = _individualDefaultCap;
}
return cap;
}
/**
* @dev Returns the amount contributed so far by a specific beneficiary.
* @param beneficiary Address of contributor
* @return Beneficiary contribution so far
*/
function getContribution(address beneficiary) public view returns (uint256) {
return _contributions[beneficiary];
}
/**
* @dev Extend parent behavior requiring purchase to respect the beneficiary's funding cap.
* @param beneficiary Token purchaser
* @param weiAmount Amount of wei contributed
*/
function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view {
super._preValidatePurchase(beneficiary, weiAmount);
// solhint-disable-next-line max-line-length
require(_contributions[beneficiary].add(weiAmount) <= getCap(beneficiary), "BOTSale: beneficiary's cap exceeded");
}
/**
* @dev Extend parent behavior to update beneficiary contributions.
* @param beneficiary Token purchaser
* @param weiAmount Amount of wei contributed
*/
function _updatePurchasingState(address beneficiary, uint256 weiAmount) internal {
super._updatePurchasingState(beneficiary, weiAmount);
_contributions[beneficiary] = _contributions[beneficiary].add(weiAmount);
}
}