NFT 표준 선택 가이드: ERC-721/1155, 분할 소유권, Dynamic NFT 설계
ERC-721과 ERC-1155의 선택 기준, Vault 기반 분할 소유권 구조, EIP-712 서명으로 상태가 바뀌는 Dynamic NFT까지 실무 설계 패턴을 정리한다.
2026-08-12 · 최초 발행 2025-12-11
토큰 하나가 자산 하나를 대표해야 하는 경우와, 같은 자산을 수천 개 단위로 찍어야 하는 경우는 설계가 완전히 다르다. NFT(Non-Fungible Token)는 온체인에서 유일성을 보장하는 토큰 규격으로, 메타데이터로 자산 특성을 표현하고 스마트컨트랙트로 소유·이전·권한을 제어한다. ERC-721/1155 표준 차이, Fractional Ownership(분할 소유권) 구조, Dynamic NFTs 설계와 운영 메커니즘을 실무 적용 관점에서 짚는다.
표준을 가르는 기준
ERC-721은 토큰 1개가 고유 아이디 1개에 대응하는, 단일성·고유성에 최적화된 표준이다. ERC-1155는 하나의 컨트랙트에서 대체성·비대체성 토큰을 동시에 관리하며, 배치 전송·민팅의 가스 비용을 최적화한다. 선택 기준은 자산의 유일성 요구, 배치 처리 필요성, 마켓 호환성이다. 동일 자산을 다수 인스턴스로 발행해야 한다면 1155가 유리하다.
메타데이터는 JSON 스키마 기반(tokenURI)으로 표현한다. 불변성이 요구되면 IPFS·Arweave에 저장하고, 동적 요구가 있으면 서명 검증·오라클 검증 흐름을 별도로 설계한다.
민팅·이전·로열티
민팅은 권한 제어(Ownable/AccessControl), 재진입 방지, 이벤트 로깅이 필수이며 배치 민팅에는 1155를 권장한다. 이전(Transfer)은 승인(approve/setApprovalForAll)과 세이프 전송, 수신자 인터페이스(ERC721Receiver/1155Receiver) 검증을 거쳐야 한다. 로열티는 EIP-2981 채택을 권장하지만 마켓별 강제 여부와 수취 로직은 서로 다르다(최신 정보 확인 필요).
쪼개서 파는 소유권: Fractionalization
Vault 패턴은 NFT를 금고에 보관하고 ERC-20 지분 토큰을 발행하며, 지분 전체가 소각되어야 원본을 회수할 수 있는 구조다. 유동성과 가격발견을 촉진한다. 거버넌스·바이아웃은 경매나 제안·투표로 바이아웃 가격을 정하는데, 규제 및 유가증권성 이슈를 함께 검토해야 한다. 리스크는 가격 조작, 유동성 고갈, 금고 키 관리, 프런트러닝 대응이다.
메타데이터가 움직이는 NFT: Dynamic NFT
상태 소스는 온체인(블록 타임·VRF)이거나 오프체인(게임 서버·IoT·스코어) 오라클이다. 갱신 모델은 컨트랙트 내 검증 가능한 서명(EIP-712) 기반 URI 갱신, 또는 온체인 SVG·속성 계산 방식을 쓴다. 무결성을 지키려면 변경 이력을 이벤트화하고, 갱신 권한을 업데이터 역할·멀티시그로 분리하며, 만료와 재플레이를 방지해야 한다.
보안·운영 모범사례
권한은 최소화해야 한다. 업그레이드 가능한 프록시를 쓸 때는 어드민을 멀티시그·타임락으로 구성한다. 입력 검증에서는 수신자 인터페이스 체크, ReentrancyGuard, 오라클 응답의 서명·타임스탬프 검증이 필요하다. 인덱싱·가시성 측면에서는 Transfer/URI 같은 이벤트 표준을 충실히 기록하고 서드파티 인덱서와의 동기화를 고려해야 한다.
표준·구조 선택 트레이드오프
| 항목 | ERC-721 | ERC-1155 | Fractionalization(Vault+ERC-20) |
|---|---|---|---|
| 성능(가스) | 단일 민팅/전송 기준 보통 | 배치 민팅/전송 우수, 다중 토큰 효율 | 초기 예치·지분 발행 비용 추가 |
| 확장성 | 토큰 다양성↑, 배치 효율↓ | 동일 자산 다량 발행·배치 처리 유리 | 유동성 풀 연계로 시장 확장 |
| 일관성 | 고유성 강함, 1:1 매핑 명확 | 대체·비대체 혼합 지원 | 원본-지분 동기화 규칙 필요 |
| 안정성 | 구현 단순, 표준 성숙 | 인터페이스 복합, 수신자 체크 중요 | 금고 키 관리·바이아웃 로직 위험 |
| 운영 편의 | 마켓 호환성 높음 | 게임/티켓 등 대량 발행 편의 | 규제 검토·거버넌스 운영 부담 |
수치·가스 비용은 체인/L2·클라이언트 구현에 따라 달라진다(최신 정보 확인 필요).
처리 흐름
입력은 사용자 서명·메타데이터·오라클 서명이며, 권한·서명 검증 후 민팅 또는 URI 갱신이 이뤄지고 이벤트가 기록된다. 출력은 체인 상태 업데이트, 인덱싱, 마켓 표시다. 에러 처리는 Revert로 원자성을 보장하고, 인터페이스를 준수하지 않는 수신자는 차단한다.
활용 사례
게임 아이템·티켓은 다량 발행·등급별 아이템에 ERC-1155 배치 민팅을 적용하고, 서버 점검·시즌 변경에 따라 Dynamic URI를 쓴다. 에어드랍·크래프팅은 1155의 safeBatchTransferFrom과 소각·조합 규칙을 온체인화한다.
음악·IP 권리 분할은 마스터 NFT와 ERC-20 지분 발행을 결합해 스트리밍 수익 분배를 자동화하고, 바이아웃 경매로 소유권을 통합할 수 있다. 관할권별 증권성 판단과 KYC/AML 게이트가 규제 준수 요건이다.
부동산·실물 자산 토큰화는 SPV가 보유한 실물을 대표 NFT로 만들고 분할 지분을 발행하는 방식이다. 락업·화이트리스트·세이프 트랜스퍼 정책을 적용하고, 감정·가격피드는 오라클과 감사 로그로 온체인 증빙한다.
멤버십·패스는 등급·상태·참여도에 따라 동적 속성이 바뀌며, EIP-712 서명 기반의 비가역 업그레이드 절차를 쓴다. 재판매 시 소유 이전에 따른 혜택 리셋 규칙과 로열티 적용이 뒤따른다.
코드로 보는 패턴
전제조건은 Solidity ^0.8.20, OpenZeppelin Contracts ^5, Hardhat 또는 Foundry, EVM 호환 네트워크다.
Dynamic NFT(ERC-721 + EIP-712 서명 갱신)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
contract DynamicNFT is ERC721URIStorage, EIP712, Ownable {
using ECDSA for bytes32;
// 업데이터 역할 주소(멀티시그 권장)
address public updater;
mapping(uint256 => uint256) public nonces;
bytes32 private constant UPDATE_TYPEHASH =
keccak256("Update(uint256 tokenId,string uri,uint256 nonce,uint256 deadline)");
event UpdaterChanged(address indexed updater);
constructor(address initialUpdater)
ERC721("DynamicNFT", "DNFT")
EIP712("DynamicNFT", "1")
Ownable(msg.sender)
{
updater = initialUpdater;
emit UpdaterChanged(initialUpdater);
}
function setUpdater(address newUpdater) external onlyOwner {
updater = newUpdater;
emit UpdaterChanged(newUpdater);
}
function mint(address to, uint256 tokenId, string calldata uri) external onlyOwner {
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
function updateURI(
uint256 tokenId,
string calldata newUri,
uint256 deadline,
bytes calldata signature
) external {
require(_ownerOf(tokenId) != address(0), "NONEXISTENT");
require(block.timestamp <= deadline, "EXPIRED");
bytes32 structHash = keccak256(
abi.encode(
UPDATE_TYPEHASH,
tokenId,
keccak256(bytes(newUri)),
nonces[tokenId],
deadline
)
);
bytes32 digest = _hashTypedDataV4(structHash);
address signer = digest.recover(signature);
require(signer == updater, "INVALID_SIGNER");
_setTokenURI(tokenId, newUri);
unchecked {
nonces[tokenId] += 1;
}
}
}
updater는 멀티시그·타임락으로 관리하고 오라클 서버 키는 분리하는 것을 권장한다. URI 변경 시 별도 이벤트를 추가해 변경 이력을 남길 수도 있다.
ERC-1155 배치 민팅
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract My1155 is ERC1155, Ownable {
constructor(string memory baseURI) ERC1155(baseURI) Ownable(msg.sender) {}
function mintBatch(
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external onlyOwner {
_mintBatch(to, ids, amounts, data);
}
}
Fractionalization Vault(개념 스켈레톤)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract NFTVault is ERC20Burnable, ReentrancyGuard, Ownable {
IERC721 public immutable nft;
uint256 public immutable tokenId;
bool public locked;
constructor(address nft_, uint256 tokenId_, string memory name_, string memory symbol_)
ERC20(name_, symbol_)
Ownable(msg.sender)
{
nft = IERC721(nft_);
tokenId = tokenId_;
}
function depositAndFractionalize(uint256 totalShares) external onlyOwner nonReentrant {
require(!locked, "LOCKED");
nft.transferFrom(msg.sender, address(this), tokenId);
locked = true;
_mint(msg.sender, totalShares);
}
// 단순 예시: 전량 보유자만 원본 회수
function redeemAll() external nonReentrant {
uint256 supply = totalSupply();
require(balanceOf(msg.sender) == supply, "NOT_FULL_OWNER");
_burn(msg.sender, supply);
locked = false;
nft.transferFrom(address(this), msg.sender, tokenId);
}
}
실제 운영에서는 바이아웃 경매·가격 피드·화이트리스트·세금/규제 처리를 추가해야 하고, 재진입·승인·오라클 조작 방어를 강화해야 한다.
운영 트레이드오프
ERC-1155의 배치 기능을 쓰면 민팅·전송 가스를 30~70% 절감할 수 있다고 보고되지만 체인·구현에 따라 편차가 크고, 최신 정보를 확인해야 한다.
권한 모델은 소유자·업데이터 분리와 단일 키 단순성 사이에서 운영 민첩성과 키 리스크를 맞바꾼다. 메타데이터는 고정(IPFS/Arweave)의 무결성과 동적(오라클)의 유연성 사이에서 감사 범위와 신뢰 경계를 고려해야 한다. 수익·로열티는 온체인 자동 분배의 투명성과 마켓 강제력·수수료 정책 변동 리스크 사이의 문제다. 확장성 측면에서는 1155의 배치 효율과 721의 마켓 친화성·지갑 호환성이 상충한다.
고유성과 마켓 호환이 우선이면 ERC-721, 대량 발행과 가스 효율이 중요하면 ERC-1155를 채택한다. 분할 소유권은 Vault+ERC-20 구조로 유동성을 확대하되 거버넌스·규제·보안 설계가 필수다. 동적 NFT는 EIP-712 서명·오라클·온체인 규칙으로 신뢰 경계를 명확히 하고 변경 이력의 투명성을 확보해야 한다. 표준(EIP-721/1155/2981/712) 준수, 멀티시그 운영, 이벤트 인덱싱을 기본으로 하고, 체인/L2 수수료와 마켓 정책은 최신 정보를 확인해 도입한다.