Hi,
I’m working with solidity and ether contracts for the first time, so I’m going through the documentation and working through some simple tutorials. Although I’m learning quite a bit, I have no idea why I am unable to run a transfer of my ERC20 token. The exact error running my integration test is Error: Returned error: VM Exception while processing transaction: revert
. It is clear that it is getting tripped up at the transfer line of the ArkICO contract, but to my knowledge, ‘transfer’ doesn’t need the approval ‘transferFrom’ needs? I also moved the transfer line directly into the test, and it is able to move the tokens to the userAddr, but obviously doesn’t subtract the value from the ICO contract. Or could it be because I’m initiating the transfer from a test?
Any guidance would be greatly appreciated.
Environment
openzeppelin/contracts: “^3.4.1”
Truffle v5.2.4
solidity 0.6.0
Details
Code to reproduce
ArkToken.sol
The following contract is the token itself, and I have added a function ‘fundICO’ to be run on migration to transfer tokens to the ICO contract.
pragma solidity 0.6.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./helpers/Owned.sol";
contract ArkToken is ERC20, Owned {
uint256 public FOR_ICO = 750000;
uint256 public FOR_FOUNDER = 250000;
constructor() public ERC20("Ark", "ARK") {
_mint(msg.sender, FOR_ICO + FOR_FOUNDER);
}
function fundICO(address _icoAddr) public onlyOwner {
transfer(_icoAddr, FOR_ICO);
}
}
ArkICO.sol
ICO contract from where I want to transfer tokens. Sets the rate of ETH to ARK, and executes the transfer.
pragma solidity 0.6.0;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./ArkToken.sol";
contract ArkICO {
using SafeMath for uint256;
ArkToken token;
uint256 public RATE = 1000;
function ArkIco(address _tokenAddr) public {
token = ArkToken(_tokenAddr);
}
receive() external payable {
uint256 _amount = _getTokenAmount(msg.value);
token.transfer(msg.sender, _amount);
}
function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) {
return _weiAmount.div(10 ** 18).mul(RATE);
}
}
2_deploy_token.js
const ArkToken = artifacts.require("ArkToken")
module.exports = (deployer) => {
deployer.deploy(ArkToken)
}
3_deploy_ico.js
On ICO deploy, I pass the ArkToken address so ICO has access to the ERC20 features, then transfer the tokens to the ICO address.
const ArkToken = artifacts.require("ArkToken")
const ArkICO = artifacts.require("ArkICO")
module.exports = (deployer) => {
deployer.deploy(ArkICO, ArkToken.address)
.then(() => {
return ArkToken.deployed()
})
.then(token => {
return token.fundICO(ArkICO.address)
})
}
test.js
Here we test the distribution which passes, however ‘can buy tokens’ throws the error at the sendTransaction line.
const ArkToken = artifacts.require("ArkToken")
const ArkICO = artifacts.require("ArkICO")
const web3 = require("web3")
const {
utils: { toWei },
} = web3
contract("token", (accounts) => {
it("distributes token supply", async () => {
const token = await ArkToken.deployed()
const ico = await ArkICO.deployed()
// accounts[0] is the same address that created the TweetherToken:
const icoBalance = await token.balanceOf.call(ico.address)
const founderBalance = await token.balanceOf.call(accounts[0])
// Make sure it holds all of the supply:
assert.equal(icoBalance.toString(), "750000")
assert.equal(founderBalance.toString(), "250000")
})
it("can buy tokens", async () => {
const token = await ArkToken.deployed()
const ico = await ArkICO.deployed()
const userAddr = accounts[1] // A random account that we control
const wei = toWei("1", "ether") // We need to specify the value in wei
await ico.sendTransaction({
from: userAddr,
value: wei,
})
const userBalance = await token.balanceOf.call(userAddr);
assert.equal(userBalance.toString(), "1000")
const icoBalance = await token.balanceOf.call(ico.address);
assert.equal(icoBalance.toString(), "749000")
})
})