모듈식 스마트 컨트랙트 설계: 다이아몬드 표준(EIP-2535) 활용 가이드
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
스마트 컨트랙트 개발
대상자
- 대상자: 스마트 컨트랙트 개발자, 복잡한 로직을 포함한 dApp 개발자
- 난이도: 중급 이상 (솔리디티 및 EVM 이해 필요)
핵심 요약
- 솔리디티의 24KB 제한 극복: 다이아몬드 표준(EIP-2535)을 통해 모듈화된 컨트랙트 로직을 'facet'으로 분리, 싱글 컨트랙트 인터페이스(다이아몬드)로 통합.
- 업그레이드 가능성: delegatecall 활용으로 상태를 하나의 컨트랙트에 유지하면서도 facet별 업그레이드 가능.
- 가스 효율성: 32바이트 스토리지 슬롯 최적화 및 작은 데이터 타입의 묶음 배치로 가스 비용 절감.
섹션별 세부 요약
1. 문제점
- 24KB 컨트랙트 크기 제한: 복잡한 로직 포함 불가.
- 업그레이드 어려움: 프록시 패턴의 한계 및 오류 가능성.
- 가스 비효율: 중복 로직으로 인한 비용 증가.
2. 다이아몬드 표준(EIP-2535)
- 모듈화: 로직을 facet(예: DepositFacet, WithdrawFacet)으로 분리.
- 다이아몬드: fallback() 함수를 통해 selector → facet 매핑으로 호출 라우팅.
- 구조:
```solidity
mapping(bytes4 => address) public selectorToFacet;
fallback() external payable {
address facet = selectorToFacet[msg.sig];
assembly { ... } // delegatecall로 facet 실행
}
```
- 장점:
- 무제한 기능 확장 가능 (24KB 제한 무시).
- 업그레이드 및 상태 관리 간결화.
3. 스토리지 최적화
- 32바이트 스토리지 슬롯 활용:
```solidity
uint64 a = 1; // 8바이트
bool b = true; // 1바이트 (패킹)
uint64 c = 2; // 8바이트
```
- 작은 데이터 타입 묶음 배치: 사용되지 않은 스토리지 공간 최소화.
4. delegatecall vs call
- call: callee 컨트랙트 상태 수정.
- delegatecall: caller 컨트랙트 상태 수정 (다이아몬드 패턴에 유리).
```solidity
(bool success, ) = otherContract.delegatecall(abi.encodeWithSignature("doSomething()"));
```
5. 예시 코드
- Diamond.sol:
```solidity
contract Diamond {
mapping(bytes4 => address) public selectorToFacet;
fallback() external payable {
address facet = selectorToFacet[msg.sig];
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
```
- Facet 예시: DepositFacet, WithdrawFacet에서 LibAppStorage 사용.
6. 배포 단계
- DepositFacet, WithdrawFacet 먼저 배포.
- Diamond.sol 배포 시 selectorToFacet 매핑.
- Remix에서 Diamond 주소로 'At Address' 접근.
7. 사용 사례
- DeFi 프로토콜, DAO, 온체인 게임, 크로스체인 브릿지.
- 장점: 모듈화, 업그레이드, 가스 효율성.
- 단점: 설치 복잡성, 툴링 부족, 하위 레벨 호출 이해 필요.
결론
- 다이아몬드 표준(EIP-2535)은 스마트 컨트랙트의 모듈화 및 업그레이드 가능성을 극대화하는 핵심 패턴.
- 배포 시 facet 분리와 delegatecall 활용이 필수적.
- 솔리디티 0.8.19 이상 사용 권장, 스토리지 최적화와 selector 매핑에 주의.