Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't send transaction even if I use an example from official Ethereum webpage

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?

like image 316
rel1x Avatar asked Feb 17 '18 15:02

rel1x


People also ask

How Ethereum transactions are validated?

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.

How much does it cost to deploy a smart contract on eth?

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.

How does smart contract work in Ethereum?

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.


2 Answers

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;
like image 94
Roman Frolov Avatar answered Sep 30 '22 04:09

Roman Frolov


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.

like image 22
Adam Kipnis Avatar answered Sep 30 '22 05:09

Adam Kipnis