Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
6
Help us understand the problem. What is going on with this article?
@yanyansk

Truffleのテストが実行できないエラーに対応する

More than 1 year has passed since last update.

ブロックチェーンアプリケーション開発の教科書のERC20準拠のトークン作成でエラーに遭遇したのでメモ。

結論

solidityのバージョンエラーとopenzeppelinのコードに変更があったことによるエラーでした。
以下のように修正することでテストが実行できました。

pragma solidity ^0.5.0;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract DappsToken is ERC20 {
  string public name = "DappsToken";
  string public symbol = "DTKN";
  uint public decimals = 18;

  constructor(uint initialSupply) public {
    _mint(msg.sender, initialSupply);
  }

}

エラー対応①

テストを実行すると以下のようなエラーが出た。

truffle(develop)> test

Compiling your contracts...
===========================
> Compiling ./contracts/DappsToken.sol
> Compiling ./contracts/Migrations.sol
> Compiling openzeppelin-solidity/contracts/ownership/Ownable.sol

SyntaxError: Source file requires different compiler version (current compiler is 0.5.0+commit.1d4f565a.Emscripten.clang - note that nightly builds are considered to be strictly less than the released version
pragma solidity ^0.4.23;
^----------------------^

DeclarationError: Identifier not found or not unique.
contract DappsToken is StandardToken {
                       ^-----------^

Error: Truffle is currently using solc 0.5.0, but one or more of your contracts specify "pragma solidity ^0.4.23".
Please update your truffle config or pragma statement(s).
(See https://truffleframework.com/docs/truffle/reference/configuration#compiler-configuration for information on
configuring Truffle to use a specific solc compiler version.)

Compilation failed. See above.

エラー内容としては、以下の2点。
- truffleの対応バージョンが0.5.0からなのでsolidityのバージョンが古い
- StandardTokenが見つからない

truffleの対応バージョンが0.5.0からなのでsolidityのバージョンが古い

バージョンを修正。

-pragma solidity ^0.4.23;
+pragma solidity ^0.5.0;

StandardTokenが見つからない

openzeppelin-solidity/contracts/token/StandardToken.sol'が正しそうだが、最新のopenzeppelinのソースコードにはStandardToken.solというファイルは無く、代わりにERC20.solというファイルが出来ていた。こちらを使うのが正しそう。

-import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
+import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

-contract DappsToken is StandardToken {
+contract DappsToken is ERC20 {

エラー対応②

上記の修正を行いもう一度テストするとまたエラー。

Compiling your contracts...
===========================
> Compiling ./contracts/DappsToken.sol
> Compiling ./contracts/Migrations.sol
> Compiling openzeppelin-solidity/contracts/math/SafeMath.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/IERC20.sol

DeclarationError: Undeclared identifier. Did you mean "totalSupply"?
    totalSupply_ = initialSupply;
    ^----------^

DeclarationError: Undeclared identifier. Did you mean "balanceOf"?
    balances[msg.sender] = initialSupply;
    ^------^

Compilation failed. See above.

totalSupplyとbalancesが無い

openzeppelin-solidity/contracts/token/ERC20/BasicToken.solにinternalのmapping, 変数として定義されていたため、継承先でも触ることが出来たが、最新版ではprivateで定義されているため参照出来ない。

openzeppelin-solidity/BasicToken.sol at v1.12.0 · OpenZeppelin/openzeppelin-solidity · GitHub

mapping(address => uint256) internal balances;

uint256 internal totalSupply_;

openzeppelin-solidity/ERC20.sol at master · OpenZeppelin/openzeppelin-solidity · GitHub

mapping (address => uint256) private _balances;

mapping (address => mapping (address => uint256)) private _allowed;

uint256 private _totalSupply;

代わりにmintという関数で同様の処理を行うことができそう。

/**
 * @dev Internal function that mints an amount of the token and assigns it to
 * an account. This encapsulates the modification of balances such that the
 * proper events are emitted.
 * @param account The account that will receive the created tokens.
 * @param value The amount that will be created.
 */
function _mint(address account, uint256 value) internal {
    require(account != address(0), "ERC20: mint to the zero address");

    _totalSupply = _totalSupply.add(value);
    _balances[account] = _balances[account].add(value);
    emit Transfer(address(0), account, value);
}

下記のように修正。

-    totalSupply_ = initialSupply;
-    balances[msg.sender] = initialSupply;
+    _mint(msg.sender, initialSupply);

無事に実行できた。

truffle(develop)> test

Compiling your contracts...
===========================
> Compiling ./contracts/DappsToken.sol
> Compiling ./contracts/Migrations.sol
> Compiling openzeppelin-solidity/contracts/math/SafeMath.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
> Artifacts written to /var/folders/05/8v72f98537x82ygl33y3_xzw0000gp/T/test-11942-93269-g4qlu1.bbje4
> Compiled successfully using:
   - solc: 0.5.0+commit.1d4f565a.Emscripten.clang



  0 passing (0ms)

最終的には下記のように変更することでテストが実行できた。

pragma solidity ^0.5.0;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";

contract DappsToken is ERC20 {
  string public name = "DappsToken";
  string public symbol = "DTKN";
  uint public decimals = 18;

  constructor(uint initialSupply) public {
    _mint(msg.sender, initialSupply);
  }

}

参考

OpenZeppelinを活用してセキュアのコントラクトを書く - Qiita
GitHub - OpenZeppelin/openzeppelin-solidity: OpenZeppelin is a library for secure smart contract development
ブロックチェーンアプリケーション開発の教科書 | 加嵜 長門, 篠原 航, 丸山 弘詩 |本 | 通販 | Amazon

6
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
yanyansk

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
6
Help us understand the problem. What is going on with this article?