이더리움 블록체인은 디지털 자산의 생성 및 관리 방식을 크게 변화시켰습니다. 이러한 발전 중에서도 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의 주요 장점은 다음과 같습니다:
일괄 전송(Batch Transfers): ERC-1155는 일괄 전송을 지원하여 단일 트랜잭션으로 여러 토큰 유형을 이동할 수 있습니다. 이를 통해 가스 비용이 크게 절감되고 트랜잭션 속도가 향상됩니다.
단일 컨트랙트로 다중 토큰 관리: 이 표준을 사용하면 단일 컨트랙트로 fungible 토큰과 non-fungible 토큰을 모두 관리할 수 있어 배포가 간소화되고 비용이 절감됩니다.
안전한 전송 검사(Safe Transfer Checks): ERC-1155는 토큰이 호환 가능한 주소로 전송되도록 보장하여 트랜잭션 안전성을 높이고 오류로 인한 손실을 방지합니다.
ERC-1155의 실제 활용 사례는 다음과 같습니다:
게임: 소모품부터 희귀 장비까지 게임 내 아이템 전체 경제를 하나의 컨트랙트 내에서 관리할 수 있습니다.
디지털 아트: 아티스트가 한정판 및 오픈 에디션 작품을 모두 원활하게 발행할 수 있습니다.
토큰화 자산: 실물 자산을 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는 이더리움 토큰 표준의 중요한 발전을 나타내며, 이전 표준보다 더 높은 유연성, 효율성, 활용성을 제공합니다. RAD Token 예제는 단일 컨트랙트 하에서 여러 토큰 유형을 얼마나 쉽게 관리할 수 있는지를 보여주며, 새로운 세대의 탈중앙화 애플리케이션을 위한 문을 열어줍니다.
유용한 리소스