//tips
//smart contract
構造理解の続き。burnの中身について確認する。今まではburnというと削除の意味合いで捉えていたが、mapping_tokenApprovalsを初期化し、ゼロアドレスに設定。
このゼロアドレス0x00000…はコントラクトの生成時だけではなく、burnの時にも使用するよう。
https://stackoverflow.com/questions/48219716/what-is-address0-in-solidity
https://ethereum.stackexchange.com/questions/42717/what-does-address0-mean
そのためburnは削除ではなく転送であるため、供給量を示したい時には_totalSupply - balances[address(0)] としなければ正確な数値は示せない。
Burnの流れとしてはownerを取得。ゼロアドレスへの転送許可approveの取得。ownerから所持トークンのマイナスと_owners[tokenId]の削除。_owners[tokenId] = address(0)ではいけなかったのかと思いdeleteについて調べてみると同じことだとわかった。
下記のようにdeleteは変数の初期値を返すので自然に address(0)になるとのこと。
delete is actually not really deletion at all - it's only assigning a default value back to variables. It does not make difference whether the variable is in memory or in storage.
For example, issuing a delete to a uint variable simply sets the variable's value to 0.
https://ethereum.stackexchange.com/questions/58495/understanding-more-about-delete-keyword-in-solidity
この際のevent/emitは他の言語のイベントとは異なり、コントラクト上で発生した結果をログに保存したり、フロントに伝えるもの。
発行されたイベントはトランザクションのレシートに記録され、その際、indexed のついた引数はフィルタリングに利用でき、特定のイベントを捕捉できる。
使い方としては、eventを定義しておき、通知などを知らせたい関数処理の中で、emitしてイベントを発行することになる。
この内容をフロントエンドでキャッチして通知という形で表現する。なので、実際のブロックチェーン処理の内容ではなく結果の通知として捉えておく。以前述べたようにこの通知の受け取りは、provider.onceやcontract.onで受け取ることになる。
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
// Clear approvals
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
_afterTokenTransfer(owner, address(0), tokenId);
}
burnしたERC721トークンはOpenSeaなどでも見ることができて、0x00…のNullAddressというアカウントに溜められているとのこと。これは知らなかった。
ベースのコントラクトを確認するとかなり勉強になった。
Ethも確保できたので、本番環境への画像アップ作業を行なっていく。先にテスト環境で行ったものを本番環境仕様に変えていけば良い。
これができれば自由にオリジナルNFTがdeployできることになる。
まずはinfuraのendpointsをmainetへ変更。.envの設定も更新しておく。
Pinataへのmetadataのアップロードはテスト環境の際に完了しているので、本番環境ではそのメタデータURIをブロックに埋め込む形で良さそう。
const filePath = path.join(__dirname, '../data/metadata.json’);で継続。
Truffleconfigにrinkbyの設定しかないのでmainのものを設定していくことにする。
Main: {
provider: () => new HDWalletProvider(mnemonic, clientURL),
network_id: 1, //
gasPrice: 31000000000, //31 gwei
gas: 3500000,
confirmations: 2, // # of confs to wait between deployments. (default: 0)
timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
skipDryRun: true , // Skip dry run before migrations? (default: false for public nets )
networkCheckTimeout: 10000000,
}
適正な値がわからないという問題が起こったので調べてみる。
https://trufflesuite.com/docs/truffle/reference/configuration/
Gasの支払いについて再度復習。
また、今回はオークションなどではなく時間をかけてもいいので、gaspriceはstandardまたはlowにしといて問題なさそう。
知っておくべきなのは計算量の方であるgas量なのでテストアップの際のものを確認。2786053+250154程度がdeploy時にかかっているので、3500000で良いか。
Gaspriceはgasstationのstandardが30gweiのようなので31gweiにしておく。
confirmationsはblockのチェックをしてもらう部分だろうか。2にしておく。
https://ethgasstation.info/
// optional config values:
// gas - use gas and gasPrice if creating type 0 transactions
// gasPrice - all gas values specified in wei
// from - default address to use for any transaction Truffle makes during migrations
// skipDryRun: - set to true if you don't want to test run the migration locally before the actual migration (default: false)
// confirmations: - number of confirmations to wait between deployments (default: 0)
// timeoutBlocks: - if a transaction is not mined, keep waiting for this number of blocks (default: 50)
// deploymentPollingInterval: - duration between checks for completion of deployment transactions
// networkCheckTimeout: - amount of time for Truffle to wait for a response from the node when testing the provider (in milliseconds)
これにてtruffleconfigへ反映できたのでdeployを実行する。
一部のコードを変えているので事前にコンパイルを行うか。
truffle compile [--list <filter>] [--all] [--network <name>] [--quiet]
https://trufflesuite.com/docs/truffle/getting-started/using-truffle-develop-and-the-console/
Truffle consoleでmigrateのresetを行うか考えたが、動画を確認しても下記のコマンドで実行できていたことからこのままトライしてみる。
npx truffle console --network mainnet
migrate
const art=await ArtCollectible.deployed()
await art.claimItem(‘https://ipfs.io/ipfs/QmXYfhz3uup6Hd4PnbVsHowiDGoh8yYDhR2QCvXZU7J56Z’)
これを実行するとエラーが発生。
/Users/akihironakamura/nft-demo/node_modules/eth-block-tracker/src/polling.js:51
const newErr = new Error(`PollingBlockTracker - encountered an error while attempting to update latest block:\n${err.stack}`)
^
Error: PollingBlockTracker - encountered an error while attempting to update latest block:
undefined
at PollingBlockTracker._performSync (/Users/akihironakamura/nft-demo/node_modules/eth-block-tracker/src/polling.js:51:24)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
Infuraの問題で起こるよう。
https://community.infura.io/t/error-pollingblocktracker-encountered-an-error-while-attempting-to-update-latest-block/4215/2
すでにinfuraをmiannetの設定に変えているので、compileがしっかりされていな為怒っているのではないかと推測。
npx truffle console --network mainnet
compile
migrate --reset
これにより1_initial_migration.js部分は通るようになった。
その後でやはり下記エラーが発生した。
Error: PollingBlockTracker - encountered an error while attempting to update latest block:
再度検索していくとMetaMask/eth-block-trackerの中身でエラーが発生していることがわかる。
https://github.com/MetaMask/eth-block-tracker/blob/main/src/PollingBlockTracker.ts
下記の部分でのエラーなのでこれを読めば要因がわかるか。
private async _synchronize(): Promise<void> {
while (this._isRunning) {
try {
await this._updateLatestBlock();
await timeout(this._pollingInterval, !this._keepEventLoopActive);
} catch (err: any) {
const newErr = new Error(
`PollingBlockTracker - encountered an error while attempting to update latest block:\n${
err.stack ?? err
}`,
);
try {
this.emit('error', newErr);
} catch (emitErr) {
console.error(newErr);
}
await timeout(this._retryTimeout, !this._keepEventLoopActive);
}
}
}
上記をみるとうまく走っていないことがわかるだけだったので、さらに検索。
Infuraでwssを使用する方がいいのではという話が出ていたのでそちらを実施してみる。
バージョンもv5以上なので問題なさそう。 "truffle": "^5.5.16"
https://community.infura.io/t/error-pollingblocktracker-causes-all-test-net-migrations-to-time-out/1968/10
No utilizar:
const INFURA_API_KEY="https://rinkeby.infura.io/xxxxxxxxx
Utilizar:
const INFURA_API_KEY="wss://rinkeby.infura.io/xxxxxxxxx
wssで試したら、でけた。結局コントラクトのデプロイ0.094122417 ETHとmint費用で総額0.1021ethかかった。
円換算すると23,629円か。
1_initial_migration.js
gas used: 250154
> gas price: 31 gwei
2_deploy_art_collectible.js
> gas used: 2786053
> gas price: 31 gwei
自分のメモを見返してみると数百円でできそうというのはmint自体の話で、テスト時のcumulativeGasUsed: 3237712にgweiをかけず総額と考えていたのが安く見積もった要因だった。気を付ける。
最初のコントラクト生成後は連続mintできるので、その際に、mintすればするほど1nftあたりのコントラクト生成費用の上乗せ/分配費は少なくて済む。10000などの数が出ているのはその分配費用分も考えてのことかとわかってきた。
最後にtruffle networksで自身のdeploy一覧を出してmainのmigrationsのハッシュをopenseaで検索。無事にトランザクションも確認できた。well done。
接続閉じたが新しく画像を作ってmintする際にはnpx truffle console --network mainnetにmigrateをせずに、const art=await ArtCollectible.deployed()はできるのかを確認する。デプロイ済みのコントラクトに接続してmintする方法を会得する。
同時にセキュリティを高くしてフロントエンドからのアクセスでmintできる構成を作る。
一旦Nft自作はできたので、snsキュレーションアプリのvercel deploy問題解決に戻る。