見出し画像

FoundryのローカルネットにゲームアイテムNFTをデプロイする

Foundryで、ゲームアイテムのNFTを作成してローカルネットにデプロイする方法を紹介します。

Foundryの初期設定がまだの方は、こちらの記事を参考にしてください。


Foundryのプロジェクトを作成します。

forge init nft_foundry


作成したプロジェクトに移動します。

cd nft_foundry


NFTの規格であるERC721を実装するために、SolmateとOpenZeppelinをインストールします。

forge install transmissions11/solmate Openzeppelin/openzeppelin-contracts


インストールが完了したフォルダー構造は下記になります。

$ tree . -L 2
.
├── README.md
├── foundry.toml
├── lib
│   ├── forge-std
│   ├── openzeppelin-contracts
│   └── solmate
├── script
│   └── Counter.s.sol
├── src
│   └── Counter.sol
└── test
    └── Counter.t.sol

8 directories, 5 files


VSCodeを開きます。

code .


src/Counter.solのファイル名をGameItem.solに変更します

mv src/Counter.sol src/GameItem.sol


NFTをミントするコードを貼り付けます。

// contracts/GameItem.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ERC721URIStorage, ERC721} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract GameItem is ERC721URIStorage {
    uint256 private _nextTokenId;

    constructor() ERC721("GameItem", "ITM") {}

    function awardItem(
        address player,
        string memory tokenURI
    ) public returns (uint256) {
        uint256 tokenId = _nextTokenId++;
        _mint(player, tokenId);
        _setTokenURI(tokenId, tokenURI);

        return tokenId;
    }
}


ビルドできるか確認します。

forge build

[⠢] Compiling...
[⠊] Compiling 1 files with Solc 0.8.28
[⠒] Solc 0.8.28 finished in 1.73s
Compiler run successful!


次にテストコードを変更します。
ファイル名をGameItem.t.solにして、テストコードを置き換えます。

// test/GameItem.t.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import {Test, console} from "forge-std/Test.sol";
import {GameItem} from "../src/GameItem.sol";

contract GameItemTest is Test {
    GameItem public gameItem;
    address public playerAddress;

    function setUp() public {
        gameItem = new GameItem();
        playerAddress = address(0x123); // テスト用のアドレス
    }

    function test_AwardItem() public {
        uint256 itemIndex = gameItem.awardItem(
            playerAddress,
            "https://game.example/item-id-8u5h2m.json"
        );
        assertEq(itemIndex, 0);
    }
}


テストコマンドを実行して、テストします。

forge test

[] Compiling...
No files changed, compilation skipped

Ran 1 test for test/GameItem.t.sol:GameItemTest
[PASS] test_AwardItem() (gas: 148104)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 21.54ms (7.22ms CPU time)

Ran 1 test suite in 364.75ms (21.54ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)


最後にローカルネットワークに、作成したNFTコントラクトをデプロイします。

anvilコマンドで、Foundryのローカルネットを立ち上げます。

anvil


                             _   _
                            (_) | |
      __ _   _ __   __   __  _  | |
     / _` | | '_ \  \ \ / / | | | |
    | (_| | | | | |  \ V /  | | | |
     \__,_| |_| |_|   \_/   |_| |_|

    0.2.0 (58bf161 2024-11-07T00:21:15.535888000Z)
    https://github.com/foundry-rs/foundry

Available Accounts
==================
(0) 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000.000000000000000000 ETH)


Private Keys
==================
(0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80


デプロイ用のスクリプトを作成します。
playerAddressにローカルのAccountsを入れます。

// script/GameItem.s.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import {Script, console} from "forge-std/Script.sol";
import {GameItem} from "../src/GameItem.sol";

contract GameItemScript is Script {
    function run() external {
        // デプロイ用のアカウントとネットワークの設定を開始
        vm.startBroadcast();

        // GameItem コントラクトをデプロイ
        GameItem gameItem = new GameItem();
        console.log("GameItem contract deployed at:", address(gameItem));

        // トークンを発行するためのプレイヤーアドレスとトークンURIを設定
        address playerAddress = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; // ローカルのアドレスに置き換えてください
        string memory tokenURI = "https://game.example/item-id-8u5h2m.json";

        // awardItem 関数を呼び出してトークンを発行
        uint256 tokenId = gameItem.awardItem(playerAddress, tokenURI);
        console.log("Awarded token ID:", tokenId);

        // 実行完了
        vm.stopBroadcast();

    }
}


以下のコマンドで、ローカルネットにデプロイします。

forge script script/GameItem.s.sol:GameItemScript --fork-url http://localhost:8545 \
--private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
--broadcast

[] Compiling...
No files changed, compilation skipped
Script ran successfully.

== Logs ==
  GameItem contract deployed at: 0x5FbDB2315678afecb367f032d93F642f64180aa3
  Awarded token ID: 0

## Setting up 1 EVM.

==========================

Chain 31337

Estimated gas price: 2.000000001 gwei

Estimated total gas used for script: 1725283

Estimated amount required: 0.003450566001725283 ETH

==========================

SIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more.

Transactions saved to: /Users/maehara/Documents/nft_foundry/broadcast/GameItem.s.sol/31337/dry-run/run-latest.json

Sensitive values saved to: /Users/maehara/Documents/nft_foundry/cache/GameItem.s.sol/31337/dry-run/run-latest.json


Castコマンドで確認します。

cast call 0x5FbDB2315678afecb367f032d93F642f64180aa3 \
"ownerOf(uint256)" 0 \
--rpc-url http://localhost:8545

0x0000000000000000000000001234567890123456789012345678901234567890


FoundryのローカルネットにアイテムNFTをデプロイできました!

参考記事


いいなと思ったら応援しよう!