即使我使用官方以太坊网页上的示例

时间:2018-02-17 15:48:31

标签: javascript ethereum solidity smartcontracts truffle

我使用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的众筹,因为它标记了一个令牌。 那么,有没有其他方法来创建一个没有铸造令牌的众筹?我认为应该有其他的方式,因为以太坊的网页上的例子没有铸造工作,但由于某种原因,它对我不起作用。我的错误在哪里?我该如何解决这个问题呢?

2 个答案:

答案 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气体,并且当您尝试做的不仅仅是记录事件时经常会失败。