Tokens

使用 Zeppelin-OS 契約創建和執行 AllowanceCrowdSale

  • September 27, 2018

我使用 openzeppelin 庫: https ://github.com/OpenZeppelin/openzeppelin-solidity/tree/v1.12.0

令牌

我創建了一個 BurnableToken:

pragma solidity 0.4.24;

import 'openzeppelin-solidity/contracts/token/ERC20/StandardBurnableToken.sol';

contract TestBurnableToken is StandardBurnableToken {
   string public name = "TestCoinBurnable";
   string public symbol = "tcb";
   uint8 public decimals = 18;

   uint256 public totalSupply;
   mapping (address => uint256) public balanceOf;

   constructor (
       uint256 initialSupply
   ) public {
       totalSupply = initialSupply * 10 ** uint256(decimals);  // Update total supply with the decimal amount
       balanceOf[msg.sender] = totalSupply;                // Give the creator all initial tokens
   }
}

創建者收到所有代幣。

眾籌

pragma solidity 0.4.24;

import './TestBurnableToken.sol';
import 'openzeppelin-solidity/contracts/crowdsale/emission/AllowanceCrowdsale.sol';
import 'openzeppelin-solidity/contracts/crowdsale/validation/TimedCrowdsale.sol';


contract TestBurnableCrowdsale is TimedCrowdsale, AllowanceCrowdsale {
   constructor
       (
           uint256 _openingTime,
           uint256 _closingTime,
           uint256 _rate,
           address _wallet,
           StandardBurnableToken _token
       )
       public
       Crowdsale(_rate, _wallet, _token)
       TimedCrowdsale(_openingTime, _closingTime)
       AllowanceCrowdsale(_wallet) {
       }
}

部署

const TestBurnableToken = artifacts.require("./TestBurnableToken.sol");
const TestBurnableCrowdsale = artifacts.require("./TestBurnableCrowdsale.sol");

module.exports = function(deployer, network, accounts) {

const openingTime = web3.eth.getBlock('latest').timestamp + 30; // two secs in the future
const closingTime = openingTime + 60 *15 // 15min
const rate = new web3.BigNumber(1000); // only ints > 0, rate seems not to be inverse
const wallet = accounts[0];


console.log("Deploying openingTime: ", openingTime, " closingTime ", closingTime, " rate ", rate, " wallet ", wallet);

return deployer
   .then(() => {
       return deployer.deploy(TestBurnableToken, 10000);
   })
   .then(() => {
       return deployer.deploy(
           TestBurnableCrowdsale,
           openingTime,
           closingTime,
           rate,
           wallet,
           TestBurnableToken.address
       );
   });
};

松露控制台

// The account that created the tokens
creator = web3.eth.accounts[0]

// The account that will buy Test tokens.
purchaser = web3.eth.accounts[2]

// The address of the Test token instance that was created when the crowdsaleInstance contract was deployed
// assign the result of TestBurnableCrowdsale.deployed() to the variable crowdsaleInstance
TestBurnableCrowdsale.deployed().then(inst => { crowdsaleInstance = inst })

crowdsaleInstance.token().then(addr => { tokenAddress = addr } )
tokenAddress

TestBurnableTokenInstance = TestBurnableToken.at(tokenAddress)

//balances before
TestBurnableTokenInstance.balanceOf(creator).then(balance => web3.fromWei(balance.toString(10)))
//this shows 10000 because 10000 tokens have been created by account[0]

TestBurnableTokenInstance.balanceOf(purchaser).then(balance => web3.fromWei(balance.toString(10)))
//this shows 0, no tokens have been bought yet


//account 0 now approves tokens to be sold
TestBurnableTokenInstance.approve(crowdsaleInstance.address,web3.toWei(1000, "ether"))
crowdsaleInstance.remainingTokens().then(balance => web3.fromWei(balance.toString(10)))
//shows that 1000 tokens of 10000 have been approved for selling

//buy and balances after buying
crowdsaleInstance.sendTransaction({ from: purchaser, value: web3.toWei(1, "ether")})
// Here I get an error: Error: VM Exception while processing transaction: revert // I also tried 0.1 and 10000 to make sure it has nothing to do with the rate

問題:為什麼最後一個控制台呼叫失敗,代幣已被眾籌合約批准account[0]訪問。

編輯

我使用了 truffles 調試功能,結果很奇怪:

31:     returns (bool)
32:   {
33:     require(_value <= balances[_from]);
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

debug(develop:0xefe253c5...)> v

  _from: '0x627306090abab3a6e1400e9345bc60c78a8bef57'
    _to: '0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef'
 _value: 1000000000000000000
       : true

debug(develop:0xefe253c5...)> 

StandardToken.sol:

35:     require(_to != address(0));
36: 
37:     balances[_from] = balances[_from].sub(_value);
                         ^^^^^^^^^^^^^^^             

debug(develop:0xefe253c5...)> v

  _from: '0x0de0b6b3a7640000'
    _to: '0x0de0b6b3a7640000'
 _value: 816
       : true

基本上_from, to,的值在行和_value之間變化。33``37

require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
require(_to != address(0));

balances[_from] = balances[_from].sub(_value);

需要更改balanceOfbalances否則 fn 將被覆蓋。

我相信您對approve函式的工作方式感到困惑。approve基本上只與transferFrom批准代幣轉移的功能結合使用 - 而不是購買。

您可以使用 Truffle 的調試功能,或者只是簡單地註釋掉require語句,直到找到罪魁禍首。

我沒有使用AllowanceCrowdsalehttps://github.com/OpenZeppelin/openzeppelin-solidity/blob/v1.12.0/contracts/crowdsale/emission/AllowanceCrowdsale.sol)的經驗,但我的猜測是那裡的require某個地方失敗了(大概_deliverTokens)。

引用自:https://ethereum.stackexchange.com/questions/57835