//tips
YouTubeにてアバタームービー第一号公開。
//smart contract
早速slitherを導入してみる。
pip3 install slither-analyzer
Slither requires Python 3.6+ and solc, the Solidity compiler.
You are using pip version 21.1.1; however, version 22.1.2 is available.
You should consider upgrading via the '/Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 -m pip install --upgrade pip' command.
バージョンが古いようなのでターミナルにてpip3 install --upgrade pipでアップグレード。
pip3 install slither-analyzer
Requirement already satisfied: slither-analyzer in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (0.8.3)
Requirement already satisfied: pysha3>=1.0.2 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from slither-analyzer) (1.0.2)
Requirement already satisfied: crytic-compile>=0.2.3 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from slither-analyzer) (0.2.3)
Requirement already satisfied: prettytable>=0.7.2 in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from slither-analyzer) (3.3.0)
Requirement already satisfied: wcwidth in /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages (from prettytable>=0.7.2->slither-analyzer) (0.2.5)
きちんと条件を満たしているというメッセージが出てきた。
slither .
を実行。これでフォルダの全てのコントラクトを検証してくれる。
Warning: This declaration shadows an existing declaration.
--> project:/contracts/ArtCollectible.sol:67:24:
|
67 | function claimItem(string memory tokenURI) public returns (uint256) {
| ^^^^^^^^^^^^^^^^^^^^^^
Note: The shadowed declaration is here:
--> project:/contracts/ArtCollectible.sol:40:5:
|
40 | function tokenURI(uint256 tokenId)
| ^ (Relevant source part starts here and spans across multiple lines).
,Warning: Visibility for constructor is ignored. If you want the contract to be non-deployable, making it "abstract" is sufficient.
--> project:/contracts/ArtCollectible.sol:18:5:
|
18 | constructor() public ERC721("artCollectible", "ARTC") {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Artifacts written to /Users/akihironakamura/nft-demo/build/contracts
> Compiled successfully using:
- solc: 0.8.14+commit.80d49f37.Emscripten.clang
ERC721._checkOnERC721Received(address,address,uint256,bytes) (@openzeppelin/contracts/token/ERC721/ERC721.sol#388-409) ignores return value by IERC721Receiver(to).onERC721Received(_msgSender(),from,tokenId,_data) (@openzeppelin/contracts/token/ERC721/ERC721.sol#395-405)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#unused-return
ArtCollectible.claimItem(string).tokenURI (ArtCollectible.sol#67) shadows:
- ArtCollectible.tokenURI(uint256) (ArtCollectible.sol#40-65) (function)
- ERC721.tokenURI(uint256) (@openzeppelin/contracts/token/ERC721/ERC721.sol#93-98) (function)
- IERC721Metadata.tokenURI(uint256) (@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol#26) (function)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#local-variable-shadowing
shadowsについて調べていくと、Name Collisionが問題となっているとのこと。名前衝突(Name Collision)とは、ある組織内のネットワークで利用している名前と、 パブリックなDNSで利用しているドメイン名が、衝突してしまう状態。
なので下記のように変数名を変更する必要がある。
name => name_ or contractName
symbol => symbol_ or contractSymbol
function claimItem(string memory tokenURI) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
_tokenURIに下線を追加した。
function claimItem(string memory _tokenURI) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, _tokenURI);
return newItemId;
}
constructor() public ERC721("artCollectible", "ARTC") {}の中身を入れていないので警告が出ている。
コントラクトが作られた時、constructorが一度だけ実行される。ここはトークンの名前とシンボルを決める箇所で空欄でも問題ないようだが、ownerを組み込んだり、baseURIを読み込むことができるよう。
address owner;
owner = msg.sender;
ちなみに継承したabstract contract Ownable is Context {で_ownerは設定されている。
address private _owner;
constructor() {
_setOwner(_msgSender());
}
constructor(string memory baseURI) ERC721("PudgyPenguins", "PPG") {
setBaseURI(baseURI);
pause(true);
}
baseURIはページの飛び先のことかと思ったが(https://pudgypenguins.com/#/)違っており、ipfsのurlのよう。urlは後で設定していくものかと思っていたが、最初に設定しておくこともでき、これで後から個別に設定する労力を割かなくてよくするとのこと。 URI = base URI + token IDとすれば自動的に個別URIを割り当てることができるため。
To set the base uri of where your metadata presides. For example, you have all your metadata hosted on a server with the endpoint as https://www.myserver.com/metadata/<token id> then your base uri is https://www.myserver.com/metadata/.
This helps to reduce the work of having to manually set the URI for each individual NFT.
https://forum.openzeppelin.com/t/what-is-setbaseuri-used-for/16294
関連してERC721にあるtransferの中の_isApprovedOrOwner関数を確認。この制約でトークンオーナーのみ転送を可能にしている。
https://note.com/fintertech/n/n3bd735e1e69e
Ownableについても確認。
最後に下記にエラーを確認。
ERC721._checkOnERC721Received(address,address,uint256,bytes) (@openzeppelin/contracts/token/ERC721/ERC721.sol#388-409) ignores return value by IERC721Receiver(to).onERC721Received(_msgSender(),from,tokenId,_data) (@openzeppelin/contracts/token/ERC721/ERC721.sol#395-405)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#unused-return
これはERC721のfunction _checkOnERC721Received(の部分に由来するもののよう。
この関数はユーザーへの送付ならば問題なく、コントラクトへの送付の場合2パターンに分岐させて異なる処理を取らせるというもの。コントラクトの関数を実行するか、コントラクトへの送金か。
The ERC721 calls this method, and now execution goes to the receiver contract to do whatever he wants. For example - staking the received token. [or more dangerously - reenter the ERC721 contarct.]
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
問題ないか。
実際にdeployされているNFTシリーズのコントラクト群が気になるのでPudgyPenguinsのものを確認。
18の下記のコントラクトから構成されている。
https://etherscan.io/address/0xbd3531da5cf5857e7cfaa92426877b022e612cf8#code
ERC721Pausable.sol
PudgyPenguins.sol
Ownable.sol
Pausable.sol
ERC721.sol
IERC721.sol
IERC721Receiver.sol
ERC721Burnable.sol
ERC721Enumerable.sol
IERC721Enumerable.sol
IERC721Metadata.sol
Address.sol
Context.sol
Counters.sol
Strings.sol
ERC165.sol
IERC165.sol
SafeMath.sol
BoredApeYachtClubも確認。PudgyPenguinsほど細かく書かれていなかった。残念。ゾンビ触りつつ見直す。
https://etherscan.io/address/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d#code