EthereumのブロックチェーンはデジタルアセットのCreationと管理を大きく変革してきました。こうした進歩の中でも、ERC-1155標準は特に注目すべきイノベーションとして登場しました。Enjinチームによって導入されたERC-1155は、単一のスマートコントラクト内でfungible、non-fungible、semi-fungibleトークンの作成を可能にすることで、ブロックチェーン全体におけるデジタルアセットの効率化と強化を目的として設計されています。
ERC-1155は、ERC-20やERC-721といった以前のトークン標準における非効率性を解消するために開発されました。ERC-20はfungibleトークン(各トークンが同一で交換可能)に、ERC-721はnon-fungibleトークン(各トークンが固有)に適していますが、これらの標準は複数のトークンタイプを扱う際のスコープと効率性に限界があります。
ERC-1155の主なメリットは以下の通りです:
バッチ転送:ERC-1155はバッチ転送をサポートしており、複数のトークンタイプを1回のトランザクションで移動できます。これによりガスコストが大幅に削減され、トランザクション速度が向上します。
複数トークンに対応した単一コントラクト:この標準により、単一のコントラクトでfungibleトークンとnon-fungibleトークンの両方を管理できるため、デプロイが簡素化されコスト削減につながります。
安全な転送チェック:ERC-1155はトークンが互換性のあるアドレスに送信されることを保証し、トランザクションの安全性を高めてエラーによる損失を防ぎます。
ERC-1155の実用的な活用例をいくつか紹介します:
ゲーム:消耗品からレアな装備まで、ゲーム内アイテムの経済圏全体を1つのコントラクトで管理できます。
デジタルアート:アーティストがリミテッドエディションとオープンエディションの両方の作品をシームレスに発行できます。
トークン化アセット:現実世界のアセットをトークン化し、ERC-1155で管理できます。
ERC-1155トークンの作成とデプロイ
このチュートリアルでは、RAD Tokenと呼ばれる基本的なERC-1155トークンを作成します。この例では、単一のコントラクトフレームワーク内でさまざまなアセットを管理する方法を示します。
開発環境のセットアップ:始める前に、Node.jsとnpmがインストールされていることを確認してください。次に、Hardhatプロジェクトをセットアップします:
mkdir rad-token
cd rad-token
npm init -y
HardhatとOpenZeppelinコントラクトのインストール
npm install --save-dev hardhat
npm install @openzeppelin/contracts
Hardhatの初期化
npx hardhatプロンプトが表示されたら「Create an empty hardhat.config.js」を選択してください。
RADTokenコントラクトの作成:新しいファイルcontracts/RADToken.solを作成し、以下のコントラクトコードを貼り付けます。
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
contract RADToken is ERC1155, Ownable {
constructor(address initialOwner, string memory baseURI) ERC1155(baseURI) Ownable(initialOwner) {
}
function mint(address account, uint256 id, uint256 amount, bytes memory data)
public
onlyOwner
{
_mint(account, id, amount, data);
}
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
public
onlyOwner
{
_mintBatch(to, ids, amounts, data);
}
function setURI(string memory newuri) public onlyOwner {
_setURI(newuri);
}
function uri(uint256 tokenId) public view override returns (string memory) {
return string(abi.encodePacked(super.uri(tokenId), Strings.toString(tokenId), ".json"));
}
function burn(address account, uint256 id, uint256 amount) public onlyOwner {
_burn(account, id, amount);
}
function burnBatch(address account, uint256[] memory ids, uint256[] memory amounts)
public
onlyOwner
{
_burnBatch(account, ids, amounts);
}
}
デプロイスクリプトの作成:Hardhat Ignitionデプロイメントモジュール用に新しいファイルignition/modules/RadToken.jsを作成し、以下のコードを追加します。
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
module.exports = buildModule("RADTokenModule", (m) => {
const deployer = m.getAccount(0);
const baseURI = m.getParameter(
"baseURI",
"<https://gateway.pinata.cloud/ipfs/Qmar8RRAZ5QoVPTzvrRk9PcFSm9YKbkanxmd951nXk2bgM/>"
);
const radToken = m.contract("RADToken", [deployer, baseURI]);
return { radToken };
});
テストスクリプトの作成:コントラクトのテスト用に新しいファイルtest/RadToken.jsを作成し、以下のコードを追加します:
const { expect } = require("chai");
const { ethers } = require("hardhat");
const {
loadFixture,
} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
describe("RADToken", function () {
async function deployRADTokenFixture() {
const [owner, addr1, addr2, ...addrs] = await ethers.getSigners();
const RADToken = await ethers.getContractFactory("RADToken");
const baseURI =
"https://gateway.pinata.cloud/ipfs/Qmar8RRAZ5QoVPTzvrRk9PcFSm9YKbkanxmd951nXk2bgM/";
const radToken = await RADToken.deploy(owner.address, baseURI);
return { radToken, owner, addr1, addr2, addrs };
}
describe("Minting", function () {
it("Should mint a token", async function () {
const { radToken, addr1 } = await loadFixture(deployRADTokenFixture);
await radToken.mint(addr1.address, 1, 100, "0x");
expect(await radToken.balanceOf(addr1.address, 1)).to.equal(100);
});
it("Should mint multiple tokens in batch", async function () {
const { radToken, addr1 } = await loadFixture(deployRADTokenFixture);
await radToken.mintBatch(addr1.address, [1, 2], [100, 200], "0x");
expect(await radToken.balanceOf(addr1.address, 1)).to.equal(100);
expect(await radToken.balanceOf(addr1.address, 2)).to.equal(200);
});
});
describe("URI Management", function () {
it("Should return correct token URI", async function () {
const { radToken } = await loadFixture(deployRADTokenFixture);
expect(await radToken.uri(1)).to.equal(
"https://gateway.pinata.cloud/ipfs/Qmar8RRAZ5QoVPTzvrRk9PcFSm9YKbkanxmd951nXk2bgM/1.json"
);
});
it("Should set new URI and return correct token URI", async function () {
const { radToken } = await loadFixture(deployRADTokenFixture);
const newBaseURI = "https://newbase.uri/";
await radToken.setURI(newBaseURI);
expect(await radToken.uri(1)).to.equal("https://newbase.uri/1.json");
});
});
});
コントラクトコードのテスト:以下のコマンドでテストを実行します:
npx hardhat testRADTokenコントラクトのデプロイ:以下のコマンドでコントラクトをコンパイルしてデプロイします:
npx hardhat compile
npx hardhat ignition --network localhost --show-logs ignition/modules/RadToken.js
次のステップ
ERC-1155はEthereumのトークン標準における大きな進歩を示しており、以前の標準と比べてより高い柔軟性、効率性、そして実用性を提供します。RAD Tokenの例は、単一のコントラクトで複数のトークンタイプを管理することがいかに容易であるかを示しており、新世代の分散型アプリケーションへの扉を開いています。
参考リソース