RWA 학습맵과 ERC-4626 볼트
도입
RWA는 온체인 토큰과 오프체인 자산 사이의 시간차를 다루는 영역이다. token balance가 있다고 해서 즉시 현금화 가능한 자산이 있는 것은 아니고, NAV가 높다고 해서 오늘 상환 가능한 유동성이 충분한 것도 아니다. 이 구분을 놓치면 stablecoin reserve, yield vault, permissioned transfer를 모두 잘못 설계하게 된다.
ERC-4626은 tokenized vault의 공통 인터페이스를 제공한다. vault share는 underlying asset에 대한 지분이지 stablecoin처럼 1달러를 목표로 하는 결제 단위가 아니다. RWA 학습의 첫 단계는 이 share/asset 관계를 정확히 읽는 것이다.
학습 목표
- ERC-4626 share/asset 모델을 설명한다.
- RWA 볼트에서 NAV와 유동성이 왜 별도 문제인지 이해한다.
개념 설명
핵심 개념
- ERC-4626 share/asset 모델을 설명한다.
- RWA 볼트에서 NAV와 유동성이 왜 별도 문제인지 이해한다.
검증 지점
- share와 asset 권리가 분리되는가
- 비동기 상환 상태가 보이는가
- ERC-4626 핵심 함수를 설명했다.
실습 산출물
- RWA 학습맵과 ERC-4626 볼트 이해 점검
- RWA 학습맵과 ERC-4626 볼트 적용 과제
- permission rule이 기록되는가
RWA 트랙은 ERC-4626, ERC-7540, ERC-3643, NAV/redemption, 실무 체크리스트 순서로 읽는다. 이 순서는 권리 구조에서 시작해 상환 지연, 자격 제한, 운영 검증으로 이동한다.
| 학습 단계 | 핵심 질문 | 산출물 |
|---|---|---|
| ERC-4626 | share가 어떤 asset claim을 나타내는가 | share/asset conversion 표 |
| ERC-7540 | 입출금이 즉시 처리되지 않을 때 어떤 request 상태가 필요한가 | async redemption 상태머신 |
| ERC-3643 | 누가 token을 보유하거나 전송할 수 있는가 | identity/compliance rule 표 |
| NAV/redemption | NAV, reserve, liquidity, redemption window가 어떻게 다르게 움직이는가 | reserve evidence packet |
| 실무 체크리스트 | 출시 전에 어떤 문서와 테스트가 필요한가 | RWA Go/No-Go packet |
ERC-4626에서 핵심은 asset, share, totalAssets, conversion, preview, max limit을 분리해 읽는 것이다.
| 개념 | 의미 | 설계 질문 |
|---|---|---|
asset() | vault가 관리하는 underlying ERC-20 | 이 asset은 allowlisted token인가 |
| share | vault ERC-20 balance, underlying에 대한 지분 | 사용자가 가진 것이 dollar claim인지 vault claim인지 명확한가 |
totalAssets() | vault가 관리하는 underlying 총량 | offchain NAV나 pending redemption과 어떻게 연결되는가 |
convertToShares | 이상적 조건의 asset to share 환산 | rounding down과 fee 제외 조건을 이해했는가 |
previewDeposit | 현재 조건에서 deposit 결과 예측 | 실제 deposit 결과와 불리한 차이가 생길 수 있는가 |
maxDeposit/maxRedeem | 현재 허용 가능한 최대치 | global/user limit을 과대평가하지 않는가 |
Stablecoin과 ERC-4626 share는 같은 "토큰"처럼 보이지만 권리가 다르다.
| 항목 | Stablecoin | ERC-4626 share |
|---|---|---|
| 주요 목적 | 결제와 상환 청구권 | vault 지분 |
| 가격 모델 | 1달러 target 또는 par value | totalAssets / totalSupply에 따라 변동 |
| 상환 주체 | issuer 또는 redemption agent | vault logic과 underlying liquidity |
| 주요 위험 | reserve, issuer, freeze, redemption policy | NAV, rounding, liquidity, strategy, fee |
| 제품 설명 | "내 잔고는 얼마인가" | "내 share가 얼마의 asset claim인가" |
코드로 확인하기
RWA vault 코드는 "얼마를 넣으면 몇 share를 받는가"를 숫자로 고정한다. 강의에서 본 share/asset/NAV 관계는 previewDeposit, totalAssets, reconciliation 코드가 같은 값을 말할 때만 운영 가능한 모델이 된다.
컨트랙트ERC-4626 share 계산의 방어선
function previewDeposit(uint256 assets) public view returns (uint256 shares) { uint256 supply = totalSupply(); uint256 managedAssets = totalAssets(); if (supply == 0) { return assets; } if (managedAssets == 0) { revert NavNotPublished(); } shares = Math.mulDiv(assets, supply, managedAssets, Math.Rounding.Floor);}function deposit(uint256 assets, address receiver) public returns (uint256 shares) { shares = previewDeposit(assets); if (shares == 0) revert DustDeposit(assets); asset.safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares);}이 코드는 NAV가 비어 있는 상태에서 신규 예치가 들어오면 share 가격이 왜곡되는 문제를 먼저 막는다. 특히 RWA vault에서는 off-chain asset value가 늦게 들어올 수 있으므로, totalAssets()가 단순 token balance가 아니라 검증된 NAV snapshot을 참조하는지 봐야 한다.
백엔드custodian NAV와 on-chain totalAssets 대조
type NavSnapshot = { asOf: string; custodianAssets: bigint; onchainCash: bigint; liabilities: bigint;};function expectedTotalAssets(snapshot: NavSnapshot) { return snapshot.custodianAssets + snapshot.onchainCash - snapshot.liabilities;}function assertVaultDrift(snapshot: NavSnapshot, onchainTotalAssets: bigint) { const expected = expectedTotalAssets(snapshot); const drift = expected > onchainTotalAssets ? expected - onchainTotalAssets : onchainTotalAssets - expected; if (drift > expected / 10_000n) { throw new Error(`NAV drift too high: ${drift.toString()}`); }}백엔드 검증은 "컨트랙트가 틀렸다"를 찾는 도구가 아니라, 컨트랙트가 신뢰하는 off-chain 수치가 충분히 최신이고 일관적인지 확인하는 운영 장치다.
강의 포인트
| 관점 | 확인할 질문 | 증거로 남길 것 |
|---|---|---|
| 토큰 권리 | 사용자의 token이 stablecoin balance인지 vault share인지 구분했는가 | rights matrix |
| NAV 시점 | totalAssets()와 offchain NAV 산정 시점이 어떻게 다른가 | NAV timestamp policy |
| 환산 | conversion과 preview 함수의 rounding/fee 의미를 설명할 수 있는가 | conversion test case |
| 한도 | maxDeposit, maxWithdraw, maxRedeem이 실제 제한보다 높게 나오지 않는가 | limit checklist |
| reserve 연결 | issuer reserve asset과 holder liability를 분리했는가 | reserve data model |
실무 예시
스테이블코인 issuer가 준비자산 일부를 tokenized treasury vault에 넣는다고 가정한다. 사용자의 stablecoin balance는 vault share가 아니다. 사용자는 issuer에 대한 상환 청구권을 갖고, issuer가 reserve portfolio 안에서 vault share를 보유한다.
| 잘못된 설계 | 왜 위험한가 | 바른 설계 방향 |
|---|---|---|
| vault share를 stablecoin holder에게 직접 1:1 대응 | share price 하락과 withdrawal delay를 holder가 이해할 수 없다 | reserve asset과 liability를 분리한다 |
| NAV만 보고 즉시 상환 가능하다고 표시 | NAV는 가격이고 liquidity는 현금화 가능성이다 | redemption window와 available liquidity를 따로 표시한다 |
| preview 값을 확정 수령액으로 안내 | preview와 execution 사이에 fee, slippage, limit이 달라질 수 있다 | expected amount와 final amount를 분리한다 |
| permissioned asset을 DeFi collateral처럼 취급 | transfer restriction과 investor eligibility를 무시한다 | token support와 compliance rule을 먼저 확인한다 |
흔한 오해와 실패 시나리오
| 오해 | 실제로 확인할 것 |
|---|---|
| ERC-4626 share도 stablecoin처럼 1달러로 보면 된다고 생각한다. | share는 vault 지분이며 price per share가 변한다. |
totalAssets()가 항상 실시간 NAV라고 본다. | onchain accounting, offchain NAV, pending request가 서로 다른 시점을 가질 수 있다. |
| preview 함수 결과를 guaranteed amount처럼 보여준다. | preview와 실제 실행 결과의 관계, rounding, fee, limit을 테스트해야 한다. |
| first deposit과 donation attack을 무시한다. | 초기 share price 조작과 외부 donation이 depositor에게 불리하게 작동할 수 있다. |
| reserve asset 보유와 holder 상환 가능성을 같은 말로 쓴다. | reserve composition, liquidity, redemption policy를 따로 관리해야 한다. |
실습 과제
- RWA 학습맵과 ERC-4626 볼트 이해 점검: share, asset, totalAssets, conversion, preview, max limit의 의미를 표로 정리한다.
- RWA vault 데이터 모델 설계: vaultAddress, assetAddress, shareDecimals, assetDecimals, totalAssets, totalSupply, navTimestamp, feePolicy, maxRedeem을 포함한 데이터 모델을 만든다.
- conversion 테스트 작성: 6 decimals stablecoin을 underlying으로 가정하고 첫 deposit, donation, previewWithdraw, rounding case를 테스트 시나리오로 쓴다.
- reserve 연결 메모 작성: stablecoin liability와 vault reserve asset을 어떻게 dashboard에서 분리할지 설명한다.
완료 기준
- ERC-4626 핵심 함수를 설명했다.
- NAV와 유동성 차이를 정리했다.
- 데이터 모델 초안을 만들었다.
근거 자료
- RWA 학습맵: 04-RWA-토큰화/00-RWA-학습맵.md
- ERC4626 토큰화 볼트: 04-RWA-토큰화/01-ERC4626-토큰화-볼트.md
- ERC-4626: Tokenized Vault Standard: https://eips.ethereum.org/EIPS/eip-4626