ERC-8042 다이아몬드 스토리지 (Diamond Storage)

Final · 기타 · 2025-10-11 작성

사람이 읽을 수 있는 문자열의 keccak256 해시값을 구조체의 저장 위치로 쓰는 다이아몬드 스토리지 패턴을 표준으로 정합니다. 하나의 컨트랙트 안에서 저장 공간을 구역별로 나눠 관리할 수 있게 합니다.

왜 필요한가

스마트 컨트랙트는 데이터를 저장소(storage)라는 공간에 보관하는데, 여러 기능 모듈이 한 저장소를 함께 쓰는 프록시(proxy) 구조에서는 서로 다른 모듈이 같은 자리에 데이터를 써서 덮어쓰는 사고가 날 수 있습니다. 2020년 3월 솔리디티 컴파일러가 구조체를 저장소의 임의 위치에 둘 수 있게 되면서 읽기 쉬운 문자열을 해시해 위치를 정하는 다이아몬드 스토리지 패턴이 생겼고 ERC-2535 다이아몬드를 통해 널리 쓰였습니다. 그러나 이 방식은 오랫동안 정식 표준이 아니었고 2023년에 나온 ERC-7201은 같은 목적의 패턴을 표준화했지만 이미 쓰이던 다이아몬드 스토리지와 다른 계산 공식을 제안했습니다. 그 결과 운영 중인 기존 구현들은 표준의 보호를 받지 못했습니다. 이 표준은 단순하고 검증된 원래 방식을 명문화해 새 프로젝트가 쓸 수 있게 하고 과거 구현도 표준으로 인정합니다.

심층 설명

저장 위치 공식과 식별자 규칙

다이아몬드 스토리지 식별자는 출력 가능한 ASCII 문자(0x20부터 0x7E까지)만 담은 문자열입니다. 구조체의 저장 위치는 이 식별자의 keccak256 해시로 정해집니다. 즉 공식은 erc8042(id) = keccak256(id) 하나이며 솔리디티 표현으로는 keccak256(id)입니다. ERC-7201의 다단계 공식과 달리 해시 한 번으로 위치가 나오므로 계산이 단순하고 검증하기 쉽습니다.

권고 사항 네 가지

첫째, 솔리디티 문자열 리터럴을 쓰는 것을 권장합니다. 컴파일러가 출력 가능한 ASCII만 허용하도록 강제하기 때문이며 bytes32 constant STORAGE_POSITION = keccak256("myproject.erc721.registry")처럼 컴파일 타임 상수로 두는 것을 권장합니다. 16진수(\xNN)와 유니코드(\uNNNN) 이스케이프는 쓰지 않아야 합니다. 둘째, 식별자는 고유하고 사람이 읽을 수 있으며 의미 있는 문자열이어야 합니다. "car.fish.piano.run"처럼 무작위한 문자열은 의미 있는 문자열이 아닙니다. 셋째, 유니코드 리터럴(unicode"...")은 보이지 않는 문자나 비ASCII 문자를 담을 수 있어 쓰지 않아야 합니다. 넷째, 공백 문자(0x20)는 NatSpec 태그 같은 도구와 충돌할 수 있어 권장하지 않습니다.

NatSpec 태그 erc8042

ERC-7201이 정의한 @custom:storage-location <FORMULA_ID>:<NAMESPACE_ID> 태그 체계를 그대로 씁니다. 공식 식별자 erc8042는 erc8042(id: string literal) = keccak256(id)로 정의되며 주석은 @custom:storage-location erc8042:<NAMESPACE_ID> 형태가 됩니다. 예를 들어 @custom:storage-location erc8042:myproject.erc721.registry는 식별자 "myproject.erc721.registry"의 해시 위치에 뿌리를 둔 다이아몬드 스토리지를 표기합니다. 도구는 이 태그를 읽어 저장소 안 데이터의 위치를 파악할 수 있습니다.

ERC-7201과의 비교

ERC-7201의 네임스페이스 id는 공백만 없으면 되고 다른 제한이 없어 무작위 바이트도 쓸 수 있습니다. 위치 공식은 keccak256(abi.encode(uint256(keccak256(bytes(namespace id))) - 1)) & ~bytes32(uint256(0xff))로, 앞부분은 솔리디티 자료형이 keccak256으로 만드는 입력과 겹치지 않게 해 임의 바이트 id를 허용하고 뒷부분은 최종 위치를 256의 배수로 맞춰 미래의 가스 최적화 여지를 둡니다. 반면 ERC-8042는 식별자를 출력 가능한 ASCII로 제한하고 keccak256 한 번으로 위치를 구합니다. 기계가 생성한 무작위 id를 쓰려면 ERC-7201이, ASCII로 강제된 읽기 쉬운 식별자와 단순한 계산을 원하면 ERC-8042가 맞습니다.

참조 구현의 접근 패턴

참조 구현 ERC721Registry는 keccak256("myproject.erc721.registry")를 상수 STORAGE_POSITION으로 두고 ERC721RegistryStorage 구조체에 erc721Contracts 배열과 registryLimit 값을 담습니다. getStorage() 함수가 인라인 어셈블리로 s.slot := position을 실행해 구조체를 그 슬롯에 연결하면, 이후 함수들은 getStorage().registryLimit처럼 일반 구조체 접근 문법으로 읽고 씁니다. 이 패턴은 프록시용으로 시작했지만 어떤 스마트 컨트랙트에서든 저장소와 데이터 접근을 조직하는 데 쓸 수 있습니다.

하위 호환성

이 표준이 기술하는 다이아몬드 스토리지는 5년간 실제로 쓰여 왔습니다. 이 표준은 명세에 부합하는 과거의 모든 다이아몬드 스토리지 사용을 인정하고 표준화합니다. 따라서 기존 프로젝트는 코드를 바꾸지 않고도 표준 준수 상태가 됩니다.

쓸 때 주의할 점

ERC 원문 · ← ERCs