ブロックチェーンアプリケーション開発の教科書の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