Truffle

Truffle test 和 Truffle dev 中的“VM Exception while processing transaction: revert”

  • March 17, 2022

這是我的問題:)

問題

“錯誤:返回錯誤:處理事務時的 VM 異常:還原”時到達傳輸函式。我認為這與我的 Crowdsale 智能合約沒有任何我的代幣 TotalSupply 的事實有關。

重現步驟

代幣智能合約:

   pragma solidity   0.5.16; 

   import "openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol";
   import "openzeppelin-solidity/contracts/token/ERC20/PausableToken.sol";

   contract TokenSPC is PausableToken, DetailedERC20 
   {

       constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _amount)
       DetailedERC20(_name, _symbol, _decimals)
       public
       {

           require(_amount > 0, "amount has to be greater than 0");
           totalSupply_ = _amount.mul(10 ** uint256(_decimals));
           balances[msg.sender] = totalSupply_;
           emit Transfer(address(0), msg.sender, totalSupply_);


       }
   } 

眾售智能合約:


   pragma solidity 0.5.16;

   import './TokenSPC.sol';
   import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
   import "openzeppelin-solidity/contracts/token/ERC20/PausableToken.sol";
   import "openzeppelin-solidity/contracts/crowdsale/Crowdsale.sol";
   import "openzeppelin-solidity/contracts/crowdsale/validation/CappedCrowdsale.sol";


   contract TokenCrowdsale is Crowdsale, CappedCrowdsale {

     //Minim invest contrib
     //Max invest contrib
     uint256 public investorMinCap = 2000000000000000;
     uint256 public investorHardCap = 50000000000000000000;
     mapping(address => uint256) public contributions;

     constructor(
       uint256 _rate,
       address payable _wallet,
       ERC20 _token,
       uint256 _cap
      )
     Crowdsale(_rate, _wallet, _token)
     CappedCrowdsale(_cap)
     public
     {

     }

     function getUserContribution(address _beneficiary)
     public view returns(uint256)
     {
       return contributions[_beneficiary];
     }

     function _preValidatePurchase(
       address _beneficiary, 
       uint256 _weiAmount
    )
    internal
    {
       super._preValidatePurchase(_beneficiary,_weiAmount);
       uint256 _existingContribution = contributions[_beneficiary];
       uint256 _newContribution = _existingContribution.add(_weiAmount);
       require(_newContribution >= investorMinCap && _newContribution <= investorHardCap);
       contributions[_beneficiary] = _newContribution;
    } 
  }

測試 Crowdsale.test :

import ether from './helpers/ether';
import sendTransaction from './helpers/sendTransaction';
import EVMRevert from './helpers/EVMRevert';

const BN = web3.utils.BN;

require('chai')
 .use(require('chai-as-promised'))
 .use(require('chai-bn')(BN))
 .should();

const Token = artifacts.require('TokenSPC');
const TokenCrowdsale = artifacts.require('TokenCrowdsale');

contract('TokenCrowdsale', function([_, wallet, investor1, investor2]) {

 /*before(async function() {
   // Transfer extra ether to investor1's account for testing
   await web3.eth.sendTransaction({ from: _, to: investor1, value: ether(60) })
   await web3.eth.sendTransaction({ from: _, to: investor2, value: ether(20) })
 });*/

 beforeEach(async function () {
   // Token config
   this.name = "Seed Project Coin";
   this.symbol = "SPC";
   this.decimals = 18;
   this.amount = 380000000;


   // Deploy Token
   this.token = await Token.new(
     this.name,
     this.symbol,
     this.decimals,
     this.amount
   );

   // Crowdsale config
   this.rate = new BN(500);
   this.wallet = wallet;
   this.cap = ether(100);

   //Invest cap
   this.investorMinCap = ether(0.002);
   this.investorHardCap = ether(50);

   this.crowdsale = await TokenCrowdsale.new(
     this.rate,
     this.wallet,
     this.token.address,
     this.cap


   );

   // Transfer token owern to crowdsale
   await this.token.transferOwnership(this.crowdsale.address);


 });

 describe('token', function() {
   it("should check totalSupply", async function() {
     const _supp = await this.token.totalSupply();
     console.log( "     ", "totalSupply =", _supp.toString());
   });

 });

 describe('crowdsale', function() {
   it('tracks the rate', async function() {
     const _rate = await this.crowdsale.rate();
     //console.log( "     ", "Rate =", _rate );
     //console.log( "     ", "this.rate =", this.rate );
     _rate.should.be.a.bignumber.that.equals(this.rate);
   });

   it('tracks the wallet', async function() {
     const wallet = await this.crowdsale.wallet();
     wallet.should.equal(this.wallet);
   });

   it('tracks the token', async function() {
     const token = await this.crowdsale.token();
     token.should.equal(this.token.address);
   });
 });

 //A revoir---------------------------------------------
/* describe('actualization crowdsale', function() {
   it('actualize total supply of crowdsale after purchase', async function() {
     const originalTotalSupply = await this.token.totalSupply();
     this.token.totalSupply_ -= 1;
     const newTotalSupply = await this.token.totalSupply();
     assert.isTrue(newTotalSupply < originalTotalSupply)
   });
 });*/

 describe('capped crowdsale', async function() {
   it('has the correct hard cap', async function() {
     const _cap = await this.crowdsale.cap();
     _cap.should.be.a.bignumber.that.equals(this.cap);
   });
 });

 //A revoir ---------------------------------------------
 /*describe('accepting payments', function() {
   it('should accept payments', async function() {
     const value = ether(1);
     const purchaser = investor2;
     await this.crowdsale.sendTransaction({ value : value, from : investor1}).should.be.fulfilled;
     await this.crowdsale.buyTokens(investor1, { value: value, from: purchaser }).should.be.fulfilled;
   });
 });*/

 describe('buyTokens()', function() {
   describe('when the contrib is less than min cap', function(){
     it('rejects the transaction', async function() {
       const value = this.investorMinCap - 1;
       await this.crowdsale.buyTokens(investor2, { value: value, from: investor2 }).should.be.rejectedWith(EVMRevert);
     });
   });

    describe('when the invest has already met the min cap', function(){
     it('allows the invest to contrib below the min cap', async function() {
       //isvalid
       const value1 = ether(1);


       await this.crowdsale.buyTokens(investor1, { value: value1, from: investor1 });
       console.log( "     ", "inv =", investor1 );
       console.log( "     ", "value =", value1 );
       console.log( "     ", "inv.value =", await this.crowdsale.buyTokens(investor1, { value: value1, from: investor1 }) );
       //is less then invest cap
       const value2 = 1; //wei
       await this.crowdsale.buyTokens(investor1, { value: value2, from: investor1 }).should.be.fulfilled;

     });
   });

 });

/*---------------A revoir
 describe('when the total contrib exceed the invest hardcap', function(){
   it('reject the transaction', async function() {
     //first contrib in valid range
     const value1 = ether(2);
     await this.crowdsale.buyTokens(investor1, { value: value1, from: investor1});

     //second is over hardcap
     const value2 = ether(49);
     await this.crowdsale.buyTokens(investor1, { value: value2, from: investor1}).should.be.rejectedWith(EVMRevert);
   });
 });

 describe('when the contrib is within the valid range', function() {
   const value = ether(2);
   it('succeeds & updates the contrib amount', async function() {
     await this.crowdsale.buyTokens(investor2, { value: value, from: investor2 }).should.be.fulfilled;
     const contribution = await this.crowdsale.getUserContribution(investor2);
     contribution.should.be.bignumber.equals;
   });
 });
*/

});

部署腳本:


const Token = artifacts.require("./TokenSPC.sol");
const TokenCrowdsale = artifacts.require("./TokenCrowdsale.sol");

const ether = (n) => new web3.utils.BN(web3.utils.toWei(n.toString(), 'ether'));

const duration = {
 seconds: function (val) { return val; },
 minutes: function (val) { return val * this.seconds(60); },
 hours: function (val) { return val * this.minutes(60); },
 days: function (val) { return val * this.hours(24); },
 weeks: function (val) { return val * this.days(7); },
 years: function (val) { return val * this.days(365); },
};

module.exports = async function(deployer, network, accounts) {
 const _name = "Seed Project Coin";
 const _symbol = "SPC";
 const _decimals = 18;
 const _amount = 380000000;

 await deployer.deploy(Token , _name, _symbol, _decimals, _amount );
 const deployedToken = await Token.deployed();



 const _rate           = 1;
 const _wallet         = accounts[0]; // TODO: Replace me
 const _token          = deployedToken.address;
 const _cap            = ether(100);

 await deployer.deploy(
   TokenCrowdsale,
   _rate,
   _wallet,
   _token,
   _cap

 );

 return true;
};

出現錯誤的第一種方法:

通過 cmd 啟動 ganache-cli:ganache-cli

編譯:truffle compile

啟動測試:truffle test ./test/TokenCrowdsale.test.js

第二種方法有錯誤:

通過 cmd 啟動 ganache-cli:ganache-cli

編譯:truffle compile

遷移:truffle migrate

使用控制台:truffle console

松露控制台中的命令:

   - TokenSPC.deployed().then(instance => token = instance)
   - TokenCrowdsale.deployed().then(instance => crowdsale = instance)

   - web3.eth.getAccounts().then(function(acc){ accounts = acc }) 
   -  var tokenamount = 100 * 10**18 
   - token.transfer(accounts[1], tokenamount.toString())

   - crowdsale.buyTokens(accounts[1], { from: accounts[1], value: 10000000000000000000 })

預期行為

Crowdsale 智能合約有一個固定的總供應量,我不想要任何鑄造的代幣。所以我希望眾籌進行交易以購買代幣並將其轉移給使用者。

實際結果

2


1


無標題

環境

  • 作業系統:Windows 10
  • 乙太坊客戶端:Ganache-cli => v6.9.1, Ganache-core => v2.10.2
  • 松露版 ( truffle version): v5.1.20
  • 節點版本(node --version):v12.16.1
  • npm 版本(npm --version):v6.13.4

更多資訊

我正在學習 DappUniversity 的教程:Real World Ico 來幫助我建構我的智能合約功能。我對遇到的許多錯誤進行了大量研究,幾乎每次都能找到解決方案。但是虛擬機錯誤是廢話,並沒有說明任何事情。另外,我沒有發現任何與我類似的問題。只有一個話題指出了這樣一個事實,即大多數情況下,如果不是用氣問題,那是因為我們沒有任何代幣可以購買,這對我來說是正確的。我真的認為這是因為我的眾籌中沒有任何 totalSupply,所以他無法購買/轉讓/等…我被困住了,因為我找不到解釋如何獲得固定總數的教程或主題供應。實際上有一個真正堅持我的情況,那就是那個話題:

眾籌代幣

但是他在眾籌合約的幫助下創建了代幣合約,我不想這樣做,我也不想這樣做。我需要找到一種方法將totalSupply 從代幣合約轉移到眾籌合約,並用松露測試對其進行測試。

非常感謝您的幫助窺視!

你的眾籌合約沒有代幣可以轉移給買家。

您在測試文件中轉移了代幣合約的所有權,但總供應量仍由代幣合約部署者地址控制。從外觀上看應該是您的帳戶

$$ 0 $$. 在你的兩個合約都被實例化後,你需要做一些類似的事情:

await this.token.transfer(desiredAmountOfTokens, this.crowdsale.address)

是的,我很確定這是因為你說我的 Crowdsale 契約沒有供應。我期待從 Token.sol 智能合約進行轉賬,但實際上,我需要在測試腳本中進行嗎?所以我不能讓它成為一個自動化?我需要在部署後手動將供應從代幣轉移到眾籌嗎?

非常感謝您的寶貴時間!

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