Hi community,
I am working on distributing my token via a crowdsale, using Allownace Crowdsale for better control of our token supply. I am using an ERC20 standard contract from the latest from Open Zeppelin and a crowdsale contract from v 2.5.0 since that is the latest that was supported. My contracts compile with no issues, and I am able to run a unit test that confirms, my approve() function works. I am able to approve tokens for the crowdsale contract to use. However, when I send Eth to the crowdsale contract or when I call buyTokens() directly, I am getting the following Error:
Form the Unit testing...
From my React App I am getting the following Error:
Uncaught (in promise) Error: invalid address (argument="address", value=undefined, code=INVALID_ARGUMENT, version=address/5.5.0) (argument="spender", value=undefined, code=INVALID_ARGUMENT, version=abi/5.0.7)
If any of you guys have seen this before and can help guide me to a viable solution would be greatly appreciated.
Code to reproduce
Here is my Unit testing script:
const RedBasicPresubs = artifacts.require('RedBasicPresubs');
const Red = artifacts.require('RED');
const chai = require('./setupchai.js');
const BN = web3.utils.BN;
const expect = chai.expect;
require('dotenv').config({ path: '../.env' });
contract('RedBasicPresubs Test', function (accounts) {
const [deployerAccount, recipient, anotherAccount] = accounts;
//console.log(recipient);
it('Crowdsale Should have allowance of 1 billion RED tokens', async () => {
let instance = await RedBasicPresubs.deployed();
let redInstance = await Red.deployed();
let balanceDep = await redInstance.balanceOf(deployerAccount);
await redInstance.approve(instance.address, 1000000000);
let balance = await instance.remainingTokens();
let allowance = await redInstance.allowance(deployerAccount, instance.address);
console.log(allowance.toString());
expect(allowance).to.be.a.bignumber.equal(new BN(balance));
return expect(balanceDep).to.be.a.bignumber.equal(new BN(100000000000));
});
it('should be possible to buy one token by simply sending ether to the smart contract', async () => {
let instance = await RedBasicPresubs.deployed();
let redInstance = await Red.deployed();
//let allowance = await redInstance.allowance(instance.address);
let balanceDep = await redInstance.balanceOf(deployerAccount);
let recipienteRedBal = await redInstance.balanceOf(recipient);
let purchaseAmount = await web3.utils.toWei('1000', 'wei');
let balanceBefore = await instance.remainingTokens();
console.log(balanceBefore.toString());
//await redInstance.approve(instance.address, 100);
let balanceAfter = await balanceBefore.add(new BN(1000000000));
await expect(instance.sendTransaction({ from: recipient, purchaseAmount })).to.be.fulfilled;
//await expect(instance.buyTokens({ from: recipient, value: purchaseAmount })).to.be.fulfilled;
await expect(balanceAfter).to.be.a.bignumber.equal(new BN(balanceBefore + 1000000000));
await expect(recipienteRedBal).to.be.a.bignumber.equal(new BN(purchaseAmount));
return expect(instance.weiRaised()).to.eventually.be.a.bignumber.equal(new BN(1000));
});
});
Here is the code for allowance Crowdsale Contract from Open Zeppelin:
pragma solidity ^0.5.0;
import "../Crowdsale.sol";
import "../../token/ERC20/IERC20.sol";
import "../../token/ERC20/SafeERC20.sol";
import "../../math/SafeMath.sol";
import "../../math/Math.sol";
/**
* @title AllowanceCrowdsale
* @dev Extension of Crowdsale where tokens are held by a wallet, which approves an allowance to the crowdsale.
*/
contract AllowanceCrowdsale is Crowdsale {
using SafeMath for uint256;
using SafeERC20 for IERC20;
address private _tokenWallet;
/**
* @dev Constructor, takes token wallet address.
* @param tokenWallet Address holding the tokens, which has approved allowance to the crowdsale.
*/
constructor (address tokenWallet) public {
require(tokenWallet != address(0), "AllowanceCrowdsale: token wallet is the zero address");
_tokenWallet = tokenWallet;
}
/**
* @return the address of the wallet that will hold the tokens.
*/
function tokenWallet() public view returns (address) {
return _tokenWallet;
}
/**
* @dev Checks the amount of tokens left in the allowance.
* @return Amount of tokens left in the allowance
*/
function remainingTokens() public view returns (uint256) {
return Math.min(token().balanceOf(_tokenWallet), token().allowance(_tokenWallet, address(this)));
}
/**
* @dev Overrides parent behavior by transferring tokens from wallet.
* @param beneficiary Token purchaser
* @param tokenAmount Amount of tokens purchased
*/
function _deliverTokens(address beneficiary, uint256 tokenAmount) internal {
token().safeTransferFrom(_tokenWallet, beneficiary, tokenAmount);
}
}
And here is my crowdsale contract:
pragma solidity ^0.5.0;
//import "@openzeppelin/contracts/crowdsale/Crowdsale.sol";
import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol";
contract RedBasicPresubs is AllowanceCrowdsale {
constructor(
uint256 rate,
address payable wallet,
IERC20 token,
address tokenWallet // <- new argument
)
AllowanceCrowdsale(tokenWallet) // <- used here
Crowdsale(rate, wallet, token)
public
{
Environment
Truffle v5.4.33 - a development framework for Ethereum
VS Code
Solidity 0.8.11 for ERC20
Solidity 0.5.1 for Crowdsale