我使用this example编写Crowdsale。但我无法发送一个事务,我的测试失败并出现错误:
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'
我尝试将天然气价格设置为此crowdsale.sendTransaction({value, from: buyer, gas: 4712388})
之类的交易,但对我没有帮助。
我的人群:
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);
}
}
我的测试(我以these tests为例):
// 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;
});
});
我的硬币:
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_;
}
}
我正在开发一个“博彩公司”,其中一个众筹代表一个事件。这意味着我将创建数十个众筹,我不能使用Zeppelin的众筹,因为它标记了一个令牌。 那么,有没有其他方法来创建一个没有铸造令牌的众筹?我认为应该有其他的方式,因为以太坊的网页上的例子没有铸造工作,但由于某种原因,它对我不起作用。我的错误在哪里?我该如何解决这个问题呢?
答案 0 :(得分:2)
据我了解你的问题,你正试图向你的众包合同发送一些资金。
更改此行:
await crowdsale.sendTransaction({value, from: buyer, gas: 4712388}).should.be.fulfilled;
对此:
await web3.eth.sendTransaction({
from: buyer,
to: crowdsale,
value: value,
gas: 4712388
}).should.be.fulfilled;
答案 1 :(得分:2)
首先,您的测试用例有一个错误。您发送的是受益人帐户的地址,而不是令牌合同的地址。
crowdsale = await Crowdsale.new(beneficiary, 200, 30, 1, tokenReward);
应该是
crowdsale = await Crowdsale.new(beneficiary, 200, 30, 1, token.address);
其次,正如所写的那样,由于某些原因,您将在交易本身中失败。您的后备功能正在尝试使用tokenReward.transfer(msg.sender, amount / price);
转移令牌,然后硬币合约的transfer
方法会使用require(_value <= balances[msg.sender]);
检查余额。 msg.sender
的两个值不同。在第一次使用中,msg.sender
将是buyer
的值。但是,在第二次使用时,msg.sender
是令牌合同的地址。 msg.sender
是邮件的发件人,而不是交易的原始发件人。
来自Solidity docs:
每个外部函数调用都可以更改msg的所有成员的值,包括msg.sender和msg.value。这包括调用库函数。
例如,如果地址A调用合同B,然后调用合同C. msg.sender
的值将是合同B内的A,但它是合同C中的合同B的地址。
transfer
只能由令牌所有者直接调用。对于您的使用案例,您可以先拨打approve
,然后拨打transferFrom
,或者由于您使用的是MintableToken
,您可以改为使用代币。您已经在使用Zeppelin库,因此请查看buyTokens
合约中的CrowdSale
函数。
最后要注意的是,在回退功能中加入太多逻辑绝不是一个好主意。它们仅限于2300气体,并且当您尝试做的不仅仅是记录事件时经常会失败。