I write Crowdsale using this example. But I can't send a transaction, my test fails with an error:
Contract: Crowdsale should accept payments after start:
AssertionError: expected promise to be fulfilled but it was rejected with 'Error: VM Exception while processing the transaction: revert'
I tried to set gas price to the transaction like this crowdsale.sendTransaction({value, from: buyer, gas: 4712388})
but it doesn't help me.
My Crowdsale:
pragma solidity ^0.4.16;
interface token {
function transfer(address receiver, uint amount) external;
}
contract Crowdsale {
address public beneficiary;
uint public fundingGoal;
uint public amountRaised;
uint public deadline;
uint public price;
token public tokenReward;
mapping(address => uint256) public balanceOf;
event FundTransfer(address backer, uint amount, bool isContribution);
function Crowdsale(
address ifSuccessfulSendTo,
uint fundingGoalInEthers,
uint durationInMinutes,
uint etherCostOfEachToken,
address addressOfTokenUsedAsReward
) public {
beneficiary = ifSuccessfulSendTo;
fundingGoal = fundingGoalInEthers * 1 ether;
deadline = now + durationInMinutes * 1 minutes;
price = etherCostOfEachToken * 1 ether;
tokenReward = token(addressOfTokenUsedAsReward);
}
function () public payable {
uint amount = msg.value;
balanceOf[msg.sender] += amount;
amountRaised += amount;
tokenReward.transfer(msg.sender, amount / price);
FundTransfer(msg.sender, amount, true);
}
}
My tests (I use these tests as an example):
// You can find all those helpers here: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers
import ether from '../helpers/ether';
import { advanceBlock } from '../helpers/advanceToBlock';
import { increaseTimeTo, duration } from '../helpers/increaseTime';
import latestTime from '../helpers/latestTime';
const BigNumber = web3.BigNumber;
const should = require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should();
const Crowdsale = artifacts.require('Crowdsale');
const Coin = artifacts.require('Coin');
contract('Crowdsale', accounts => {
let startTime;
let crowdsale;
let token;
const value = ether(8);
const buyer = accounts[1];
const tokenReward = accounts[2];
const beneficiary = accounts[2];
before(async () => {
// Advance to the next block to correctly read time in the solidity "now" function interpreted by testrpc
await advanceBlock();
});
beforeEach(async () => {
token = await Coin.new();
// Transfer an amount to address of token used as reward
const tokenRewardAmount = 1000000;
token.transfer(tokenReward, tokenRewardAmount);
startTime = latestTime() + duration.minutes(1);
crowdsale = await Crowdsale.new(beneficiary, 200, 30, 1, tokenReward);
});
it('should accept payments after start', async () => {
await increaseTimeTo(startTime);
await crowdsale.sendTransaction({value, from: buyer, gas: 4712388}).should.be.fulfilled;
});
});
My Coin:
pragma solidity ^0.4.19;
import 'zeppelin-solidity/contracts/token/ERC20/MintableToken.sol';
contract Coin is MintableToken {
uint8 public decimals = 0;
uint public initialSupply = 1000000 * 10 ** uint(decimals); // 1,000,000;
string public name = "My Coin";
string public symbol = "XMY";
function Coin() public {
totalSupply_ = initialSupply;
balances[msg.sender] = totalSupply_;
}
}
I am developing a “bookmaker” where a crowdsale represents an event. It means I will create dozens of crowdsales and I can't use Zeppelin's crowdsale since it mint a token. So, is there any other ways to create a crowdsale without minting tokens? I think there should be other ways since the example from Ethereum's webpage works without minting but because of some reason, it doesn't work for me. Where is my mistake? How can I solve the problem?
Ethereum miners verify legitimate transactions and create new ether as a reward for their work. A transaction is considered verified once the miner solves a cryptographic (mathematical) puzzle.
Contract execution Considering the factors shared above, the estimated cost for smart contract deployment could be $5,000 if you want to deploy a moderate size contract. On the contrary, the estimated cost could also turn out to be $500 if you expect to make the smart contract really small and compact.
A "smart contract" is simply a program that runs on the Ethereum blockchain. It's a collection of code (its functions) and data (its state) that resides at a specific address on the Ethereum blockchain. Smart contracts are a type of Ethereum account. This means they have a balance and can be the target of transactions.
As I understand your question you are trying to send some funds to your crowdsale contract.
Change this line:
await crowdsale.sendTransaction({value, from: buyer, gas: 4712388}).should.be.fulfilled;
To this:
await web3.eth.sendTransaction({
from: buyer,
to: crowdsale,
value: value,
gas: 4712388
}).should.be.fulfilled;
First off, your test case has a bug. You're sending in the address of the beneficiary account instead of the address of your token contract.
crowdsale = await Crowdsale.new(beneficiary, 200, 30, 1, tokenReward);
should be
crowdsale = await Crowdsale.new(beneficiary, 200, 30, 1, token.address);
Second, as written, you are going to fail in the transaction itself for a couple reasons. Your fallback function is trying to transfer tokens with tokenReward.transfer(msg.sender, amount / price);
and then the coin contract's transfer
method checks the balance with require(_value <= balances[msg.sender]);
. The two values of msg.sender
are different. In the first usage, msg.sender
will be the value of buyer
. However, on the second usage, msg.sender
is the address of the token contract. msg.sender
is the sender of the message, not the original sender of the transaction.
From the Solidity docs:
The values of all members of msg, including msg.sender and msg.value can change for every external function call. This includes calls to library functions.
For example, if address A calls contract B, which then calls contract C. The value of msg.sender
will be A inside contract B, but it is the address of contract B while in contract C.
transfer
should only be called by the token owner directly. For your use case, you can either call approve
first and then call transferFrom
, or since you're using a MintableToken
, you can mint the tokens instead. You're already using the Zeppelin library, so take a look at the buyTokens
functions in their CrowdSale
contract.
One final note, it's never a good idea to put too much logic inside a fallback function. They are limited to 2300 gas and frequently fail when you try to do much more than log events.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With