【问题标题】:Truffle test gives "Error: Attempting to run transaction which calls a contract function, but recipient address ___ is not a contract address"Truffle 测试给出“错误:尝试运行调用合约函数的交易,但收件人地址 ___ 不是合约地址”
【发布时间】:2018-11-24 16:06:40
【问题描述】:

当我在终端上运行 truffle test 时,我收到以下错误 Error: Attempting to run transaction which calls a contract function, but recipient address 0x3ad2c00512808bd7fafa6dce844a583621f3df87 is not a contract address 我不明白为什么会这样,因为我的 build 文件夹是正常含义,如果我运行 truffle migrate --reset 终端中的地址是与构建文件中的地址相同。当我运行 truffle migrate 时,它​​可以工作。此外,每次我运行松露测试时,收件人地址总是会发生变化。不知道有什么可以帮忙的。

另一件事只有在我使用代码selfdestruct(admin); 时才会发生,然后我会收到此错误。管理员是 = msg.sender,这是 ganache 中的第一个帐户,所以我不知道出了什么问题。

我正在使用this 视频。我已经完成了这个人的所有其他视频,一切都很好,直到现在 15:11 分钟,他进行了最终测试,对他来说,它有效,但对我来说,它给了我上面的错误。

请大家帮忙

这是我的测试(javascript)

var CinoCoin = artifacts.require("./CinoCoin.sol");
var CinoCoinSale = artifacts.require("./CinoCoinSale.sol");


contract('CinoCoinSale', function(accounts) {
  var tokenInstance;
  var tokenSaleInstance;
  var admin = accounts[0];
  var buyer = accounts[1];
  var tokenPrice = 1000000000000000; // in wei 0.01 ether
  var tokensAvailable = 750000;
  var numberOfTokens;

  it('initializes the contract with the correct values', function() {
    return CinoCoinSale.deployed().then(function(instance) {
      tokenSaleInstance = instance;
      return tokenSaleInstance.address
    }).then(function(address) {
      assert.notEqual(address, 0x0, 'has contract address');
      return tokenSaleInstance.tokenContract();
    }).then(function(address) {
      assert.notEqual(address, 0x0, 'has token contract address');
      return tokenSaleInstance.tokenPrice();
    }).then(function(price) {
      assert.equal(price, tokenPrice, 'token price is correct');
    });
  });

  it('facilitats token buying', function() {
    return CinoCoin.deployed().then(function(instance) {
      //Grab token instance first
      tokenInstance = instance;
      return CinoCoinSale.deployed();
    }).then(function(instance) {
      //Then grab token sale instance
      tokenSaleInstance = instance;
      //Provision 75% of all tokens to the token sale contract
      return tokenInstance.transfer(tokenSaleInstance.address, tokensAvailable, { from: admin})
    }).then(function(receipt) {
      numberOfTokens = 10;
      return tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: numberOfTokens * tokenPrice })
    }).then(function(receipt) {
      assert.equal(receipt.logs.length, 1, 'triggers one event');
      assert.equal(receipt.logs[0].event, 'Sell', 'should be the "Sell" event');
      assert.equal(receipt.logs[0].args._buyer, buyer, 'logs the account that purchased the tokens');
      assert.equal(receipt.logs[0].args._amount, numberOfTokens, 'logs the number of tokens purchased');
      return tokenSaleInstance.tokensSold();
    }).then(function(amount) {
      assert.equal(amount.toNumber(), numberOfTokens, 'increments the number of tokens sold');
      return tokenInstance.balanceOf(buyer);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), numberOfTokens);
      return tokenInstance.balanceOf(tokenSaleInstance.address);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), tokensAvailable - numberOfTokens);
      //Try to buy tokens different from the ether value
      return tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: 1 });
    }).then(assert.fail).catch(function(error) {
      assert(error.message.indexOf('revert') >= 0, 'msg.value must equal number of tokens in wei');
      return tokenSaleInstance.buyTokens(800000, { from: buyer, value: numberOfTokens * tokenPrice });
    }).then(assert.fail).catch(function(error) {
      assert(error.message.indexOf('revert') >= 0, 'connot purchase more tokens than available');
    });
  });

  it('ends token sale', function () {
    return CinoCoin.deployed().then(function(instance) {
      //Grab token instance first
      tokenInstance = instance;
      return CinoCoinSale.deployed();
    }).then(function(instance) {
      //Then grab token sale instance
      tokenSaleInstance = instance;
      //try to end sale from account other than admin
      return tokenSaleInstance.endSale({ from: buyer });
    }).then(assert.fail).catch(function(error) {
      assert(error.message.indexOf('revert' >= 0, 'must be admin to end sale'));
      //End sale as admin
      return tokenSaleInstance.endSale({ from: admin });
    }).then(function(receipt) {
      return tokenInstance.balanceOf(admin);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), 999990, 'returns all unsold cino coins to admin');
      //Check that the token price was reset when selfFestruct was called
      return tokenSaleInstance.tokenPrice();
    }).then(function(price) {
      assert.equal(price.toNumber(), 0, 'token price was reset');
    });
  });
});

这是我的合约代码(solidity)

pragma solidity ^0.4.23;

import "./CinoCoin.sol";

contract CinoCoinSale {
  address admin;
  CinoCoin public tokenContract;
  uint256 public tokenPrice;
  uint256 public tokensSold;

  event Sell(address _buyer, uint256 _amount);

  function CinoCoinSale(CinoCoin _tokenContract, uint256 _tokenPrice) public {
    //Assign an admin / an external account connected to the blockchain that has certain priviliges
    admin = msg.sender;
    //Assign token contract
    tokenContract = _tokenContract;
    //Token Price how much the token will cost
    tokenPrice = _tokenPrice;
  }

  //multiply function for
  function multiply(uint x, uint y) internal pure returns (uint z) {
    require(y == 0 || (z = x * y) / y == x);
  }

  //Buy tokens
  function buyTokens(uint256 _numberOfTokens) public payable {
    //Require that the value is equal to tokens
    require(msg.value == multiply(_numberOfTokens, tokenPrice));
    //Require that there are enough tokens in the contrat
    require(tokenContract.balanceOf(this) >= _numberOfTokens);
    //Require the transfer is successful
    require(tokenContract.transfer(msg.sender, _numberOfTokens));
    //Keep track of number of tokens sold
    tokensSold += _numberOfTokens;
    //Trigger a sell event
    Sell(msg.sender, _numberOfTokens);
  }

  //ending token CinoCoinSale
  function endSale()public {
    //Only an admin can end the end the sale
    require(msg.sender == admin);
    //Transfer the amount of token in the sale back to the admin
    require(tokenContract.transfer(admin, tokenContract.balanceOf(this)));
    //Destroy contract
    selfdestruct(admin);
  }
}

当我注释掉 selfdestruct(admin); 时,它说我的测试通过了,所以这似乎是一个问题

感谢您的帮助

【问题讨论】:

  • 显示您的测试。
  • 像我所有的代码这样的测试是什么意思?或者我的终端说什么?
  • 我添加了用 javascript 编写的测试和我的可靠合同,我希望这会有所帮助
  • 我修复了它,这是自毁代码的错误,感谢您的帮助,我很高兴我修复了它

标签: javascript json ethereum solidity truffle


【解决方案1】:

很高兴您已经修复了错误。在查看您的代码时,我注意到由于大型承诺链,测试文件很难遵循。我将文件转换为 async/await,将来可能更容易维护和调试。

我还注意到您正试图通过手动检查日志并捕获恢复异常来断言已发出的事件和恢复。实际上,我编写了一个库来简化此操作,因此我也为此添加了代码。

该库可以使用 npm 安装:

npm install truffle-assertions

在此之后,新的测试代码应该可以工作了。我希望这对您的 Dapp 开发有所帮助。

const CinoCoin = artifacts.require("CinoCoin");
const CinoCoinSale = artifacts.require("CinoCoinSale");
const truffleAssert = require("truffle-assertions");

contract('CinoCoinSale', function(accounts) {
  let tokenInstance;
  let tokenSaleInstance;
  let admin = accounts[0];
  let buyer = accounts[1];
  let tokenPrice = 1000000000000000; // in wei 0.01 ether
  let tokensAvailable = 750000;

  it('initializes the contract with the correct values', async function() {
    tokenInstance = await CinoCoin.deployed();
    tokenSaleInstance = await CinoCoinSale.deployed();

    assert.notEqual(tokenSaleInstance.address, 0x0, 'has contract address');
    assert.notEqual(await tokenSaleInstance.tokenContract(), 0x0, 'has token contract address');
    assert.equal(await tokenSaleInstance.tokenPrice(), tokenPrice, 'token price is correct');
    assert.equal(await tokenSaleInstance.admin(), admin, 'admin is correct');
  });

  it('facilitates token buying', async function() {
    tokenInstance = await CinoCoin.deployed();
    tokenSaleInstance = await CinoCoinSale.deployed();
    await tokenInstance.transfer(tokenSaleInstance.address, tokensAvailable, { from: admin });

    const numberOfTokens = 10;
    const receipt = await tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: numberOfTokens * tokenPrice });

    truffleAssert.eventEmitted(receipt, 'Sell', (ev) => {
      return ev._buyer === buyer && ev._amount.toNumber() === numberOfTokens;
    });

    const tokensSold = await tokenSaleInstance.tokensSold();
    assert.equal(tokensSold.toNumber(), numberOfTokens, 'increments the number of tokens sold');

    const buyerBalance = await tokenInstance.balanceOf(tokenSaleInstance.address);
    assert.equal(buyerBalance.toNumber(), numberOfTokens);

    const tokenSaleBalance = await tokenInstance.balanceOf(tokenSaleInstance.address);
    assert.equal(tokenSaleBalance.toNumber(), tokensAvailable - numberOfTokens);

    truffleAssert.reverts(
      tokenSaleInstance.buyTokens(numberOfTokens, { from: buyer, value: 1 }),
      null,
      'msg.value must equal number of tokens in wei'
    );

    truffleAssert.reverts(
      tokenSaleInstance.buyTokens(800000, { from: buyer, value: numberOfTokens * tokenPrice }),
      null,
      'connot purchase more tokens than available'
    );
  });

  it('ends token sale', async function () {
    tokenInstance = await CinoCoin.deployed();
    tokenSaleInstance = await CinoCoinSale.deployed();

    truffleAssert.reverts(tokenSaleInstance.endSale({ from: buyer }), null, 'must be admin to end sale');

    await tokenSaleInstance.endSale({ from: admin });

    const adminBalance = await tokenInstance.balanceOf(admin);
    assert.equal(adminBalance.toNumber(), 999990, 'returns all unsold cino coins to admin');

    const tokenPrice = await tokenSaleInstance.tokenPrice();
    assert.equal(tokenPrice.toNumber(), 0, 'token price was reset');
  });
});

【讨论】:

    猜你喜欢
    • 2021-08-10
    • 2023-03-12
    • 1970-01-01
    • 2022-08-03
    • 2022-10-16
    • 2018-07-12
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多