PostDeliveryCrowdsale failing to compile

:computer: Environment
OpenZeppelin 2.5.1
Truffle v5.2.4 (core: 5.2.4)
Node v15.11.0

:memo:Details

Inheriting the PostDeliveryCrowdsale into my crowdsale contract fails to compile as can be seen below, this only happens when using PostDeliveryCrowdsale and implementing it as per the documentation.

I’d like to be able to use PostDeliveryCrowdsale to hold the tokens until the crowdsale ends and have them distributed automatically.

Compiling your contracts...
===========================
√ Fetching solc version list from solc-bin. Attempt #1
> Compiling .\contracts\MyCrowdsale.sol
√ Fetching solc version list from solc-bin. Attempt #1

InternalCompilerError: Compiled contract not found.

Compilation failed. See above.
Truffle v5.2.4 (core: 5.2.4)
Node v15.11.0

:1234: Code to reproduce

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "@openzeppelin/contracts/ownership/Ownable.sol";

import "@openzeppelin/contracts/crowdsale/Crowdsale.sol";

import "@openzeppelin/contracts/crowdsale/validation/CappedCrowdsale.sol";

import "@openzeppelin/contracts/crowdsale/validation/TimedCrowdsale.sol";

import "@openzeppelin/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol";

import "@openzeppelin/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol";

import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol";

import "@openzeppelin/contracts/access/roles/CapperRole.sol";

contract OS_PRESALE is Crowdsale, CappedCrowdsale, TimedCrowdsale, CapperRole, Ownable, PostDeliveryCrowdsale {

    using SafeMath for uint256;

    mapping(address => uint256) private _contributions;

    mapping(address => uint256) private _caps;

    

    uint256 private _individualDefaultCap;

        constructor(

        uint256 rate,            // rate, in TKNbits

        address payable wallet,  // wallet to send Ether

        //address tokenWallet,     // address holding the tokens

        IERC20 token,            // the token

        uint256 cap,             // total cap, in wei

        uint256 individualCap,   // individual cap in wei

        uint256 openingTime,     // opening time in unix epoch seconds

        uint256 closingTime      // closing time in unix epoch seconds

    )

        public

        PostDeliveryCrowdsale()

        CappedCrowdsale(cap)

        TimedCrowdsale(openingTime, closingTime)

        Crowdsale(rate, wallet, token)

        

    {

          _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), "OS Sale: 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);

    }

}
1 Like

Hi @Fursty,

I am sorry you are having this issue. I was able to compile your contract.

$ npx truffle compile

Compiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/OsPresale.sol
> Compiling @openzeppelin/contracts/GSN/Context.sol
> Compiling @openzeppelin/contracts/access/Roles.sol
> Compiling @openzeppelin/contracts/access/roles/CapperRole.sol
> Compiling @openzeppelin/contracts/crowdsale/Crowdsale.sol
> Compiling @openzeppelin/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol
> Compiling @openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol
> Compiling @openzeppelin/contracts/crowdsale/validation/CappedCrowdsale.sol
> Compiling @openzeppelin/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol
> Compiling @openzeppelin/contracts/crowdsale/validation/TimedCrowdsale.sol
> Compiling @openzeppelin/contracts/math/Math.sol
> Compiling @openzeppelin/contracts/math/SafeMath.sol
> Compiling @openzeppelin/contracts/ownership/Ownable.sol
> Compiling @openzeppelin/contracts/ownership/Secondary.sol
> Compiling @openzeppelin/contracts/token/ERC20/IERC20.sol
> Compiling @openzeppelin/contracts/token/ERC20/SafeERC20.sol
> Compiling @openzeppelin/contracts/utils/Address.sol
> Compiling @openzeppelin/contracts/utils/ReentrancyGuard.sol
> Artifacts written to /home/abcoathup/projects/forum/fursty/build/contracts
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang

I thought it might be your version of node but I also change to that version and was able to compile.

$ npx truffle version
Truffle v5.2.4 (core: 5.2.4)
Solidity v0.5.16 (solc-js)
Node v15.12.0
Web3.js v1.2.9

What version of Solidity do you have configured?

1 Like

Thanks for the prompt reply.

I’ve tried with both 0.5.5 and 0.5.16 as per your code block. Both still fail with the same message:

Compiling your contracts...
===========================
√ Fetching solc version list from solc-bin. Attempt #1
> Compiling .\contracts\MyCrowdsale copy.sol
√ Fetching solc version list from solc-bin. Attempt #1


Compilation failed. See above.
Truffle v5.2.4 (core: 5.2.4)
Node v15.11.0

Compiling your contracts...
===========================
√ Fetching solc version list from solc-bin. Attempt #1
√ Fetching solc version list from solc-bin. Attempt #1

InternalCompilerError: Compiled contract not found.

Compilation failed. See above.
Truffle v5.2.4 (core: 5.2.4)
Node v15.11.0

Versions

Truffle v5.2.4 (core: 5.2.4)
Solidity - ^0.5.5 (solc-js)
Node v15.11.0
Web3.js v1.2.9

This is pretty odd because it only happens when the PostDeliveryCrowdsale contract is used, if I comment that out it works. Even if I build a new contract inheriting ONLY this contract it fails.

Is there anything I can try to fix it? Not sure if it’s related to solcjs?

1 Like

@abcoathup ,

I’ve fixed this by changing the truffle config as follows:

solc: {

      version: "v0.5.5",

Before it was “^0.5.5”. This was then a Truffle issue and not a contract issue, I apologize for polluting the forum!

May I take this opportunity to ask a contract related question? With the contract above, how could one automate the token delivery from the PostDeliveryCrowdsale contract after the crowdsale closes? Right now, it’s working if the beneficiary goes to the Crowdsale contract and requests a token withdrawal, but doing this manually is quite cumbersome, is there a solution to automate this?

1 Like

Hi @Fursty,

I recommend creating a new topic per question, that way anyone in the community can answer.

You could use OpenZeppelin Defender (https://openzeppelin.com/defender/) to call withdrawTokens for each beneficiary.

You may want to create a batch withdraw which accepted a number of addresses.

You would need to make sure you were within the gas limit.

Though with all of these solutions you are paying the gas fees.

1 Like

Thanks @abcoathup ,

Is it possible to create a batch withdraw (I’m aware of gas fees in such case)? Since the function is singular it’d have to be a single call per address correct?

1 Like

Hi @Fursty,

It should be possible to create a batch withdraw. You would be paying the gas fees. You could take in an array of addresses to withdraw from.