docs(adr): Element 파라미터 소유권과 안전한 교체 정책 확정 - #99
Closed
0xMuang wants to merge 6 commits into
Closed
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
이 PR은 PR #90에서 제기된 Element parameter와 교체 거버넌스 문제를 최종
결정으로 정리합니다. PR #97에서 Heiji가 확인한 코드 사실과 미정으로 돌려준
질문을 구분하고, PR #98의 부분 구현이 따라야 할 기준을 명확히 합니다.
문서는 결정 완료와 결정 필요를 먼저 나눕니다. 완료된 항목은 문제,
검토한 선택지, 채택한 방향과 감수하는 trade-off를 서술합니다. 아직 수치·
상품 의미·운영 주체가 정해지지 않은 항목은 개발, 리걸, 그 외의 세 책임
영역으로만 구분합니다.
어떤 문제가 있었는가
ADR-006은 Element와 Recipe를 자산 독립적인 부품으로 만들고 자산별 정책값은
Manifest가 소유하도록 정했습니다. ADR-007은 정책 변경에 timelock, 역할 분리와
변경 이력이 필요하다고 정했습니다.
그러나 BUIDL-like 최소금액
5,000,000 ether처럼 자산별 값이 전용Element/Recipe에 들어가 있었습니다. 이 방식은 유사한 규칙을 다른 자산에
재사용하기 어렵고, 수치를 바꿀 때도 새 코드를 배포해야 합니다.
또한 token 구분 없는 Element 저장값은 어떤 자산에 어떤 설정이 적용됐는지
Manifest version, timelock과 history로 추적하기 어렵습니다. parameter가 정책
commitment에 묶이지 않으면 같은 policy ID가 서로 다른 의미를 가질 수도 있습니다.
PR #90 작성 당시에는 같은
elementId의 구현을 덮어쓸 수 있다는 문제도있었습니다. 이후 PR #89가 Element와 Recipe identity를 불변으로 만들면서 이
위험은 사라졌지만, 불변 Element에서 치명적 버그가 발견됐을 때의 교체 절차가
새 문제로 남았습니다.
PR #97에서 어디까지 확인됐는가
Heiji는
checkABI 변경 범위가 interface 한 곳, Element signature 약 25개,Engine 호출부 한 곳과 관련 테스트 약 26개라고 확인했습니다. parameter가
compiled plan과 policy hash에 포함될 수 있다는 점, 같은 Recipe version의 주소와
alias는 불변이지만
latest포인터는 즉시 바뀐다는 점도 확인했습니다.반면 자산별 값을 어디까지 Manifest로 옮길지, parameter를
factsPacked,bytes, struct 중 무엇으로 표현할지, 감독기관 질의에 어떤 자료를 제출할지는결정하지 않았습니다. 같은 Element ID의 덮어쓰기가 금지된 이후 긴급 상황에도
정상 timelock을 유지할지 역시 운영·리걸 결정으로 돌려줬습니다.
결정 완료
자산별 정책과 runtime 상태를 분리한다 — D-1, Q.1
모든 정책값·동적 상태·증빙을 Manifest에 모으면 조회 위치는 단순하지만
Manifest가 KYC evidence와 거래 중 변하는 상태까지 책임지게 됩니다. 반대로
기존처럼 자산별 설정을 Element 저장소에 유지하면 migration은 작지만 설정
변경이 Manifest의 timelock, version, history와 분리됩니다.
따라서 특정 token의 허용·거부 정책 의미를 바꾸는 값만 Manifest compiled
plan에 둡니다. 허용 관할, 최소 거래량과 자산별 최대 보유자 한도는 Manifest가
소유합니다. 투자자의 KYC·QP·제재 증빙은 TA/KYC·ONCHAINID에, 현재 보유자 수와
누적 상태는 stateful Element에, pause는 OperatorRegistry에 남깁니다.
이 선택은 자산별 bytecode 중복을 줄이고 정책 변경을 Manifest hash와 history로
추적하게 합니다. 대신 Manifest storage·compile gas와 기존 값 migration 비용을
부담합니다. 실제 gas 상한과 migration 순서는 측정 후 정해야 합니다.
parameter는 bounded bytes와 고정 schema를 사용한다 — Q.2
factsPacked만 확장하면 compact하지만 숫자와 배열이 늘수록 bit layout과migration이 복잡해집니다. Element별 struct는 타입 안전하지만 새 Element마다
core interface와 Toolkit을 변경해야 합니다. 검증 없는 자유형
bytes는 잘못된ABI와 PII 입력을 막기 어렵습니다.
따라서 크기가 제한된
bytes와 immutable schema identity를 함께 사용합니다.parameter-aware Element는 지원·필수 여부,
parameterSchemaHash, 최대 길이와schema/version 문서를 제공해야 합니다. 고정 bool·enum은
factsPacked를 계속사용할 수 있습니다.
core ABI 안정성과 확장성을 얻는 대신 Registry와 Toolkit에 schema-aware
validation을 구현해야 합니다.
현재 Element v1 ABI를 유지한다 — D-2, Q.3
check에elementId를 추가하면 한 구현이 여러 ID를 처리할 수 있고, Heiji가확인한 대로 지금 변경하는 비용도 비교적 작습니다. 하지만 현재 제품에는
multi-ID Element가 반드시 필요하다는 요구가 없습니다.
따라서 v1 ABI는 유지하고 실제 요구가 생기면
IComplianceElementV2를 별도로설계합니다. 현재 integrator migration을 피하는 대신 미래 V2 migration 가능성을
감수합니다. 단순히 지금이 싸다는 이유만으로 사용 사례가 없는 ABI를 넓히지
않는 선택입니다.
policy commitment와 배포 identity를 분리한다 — D-3, Q.4
parameter와 schema identity는 compiled plan과 policy hash에 포함합니다. Element
구현 주소와 code hash는 chainId, Engine/Registry 주소, deployment artifact와
legal package를 포함한 deployment evidence에 고정합니다.
이 방식은 정책 변경을 hash로 추적하면서 매 거래의 runtime hash 비용을 줄입니다.
대신 감사 시 policy snapshot과 deployment evidence를 함께 조회해야 합니다.
Engine의 Registry 주소와 ID binding이 불변이라는 전제가 깨지면 재검토합니다.
PII-free policy snapshot으로 판정을 재현한다 — Q.5
raw event만 보관하면 질의 때마다 event와 배포 증빙을 다시 조립해야 하고,
TA/KYC provider 기록만으로는 온체인 Engine 판정을 독립적으로 설명할 수 없습니다.
따라서 거래별 PII-free policy snapshot과 변경 history를 export합니다. Manifest,
Recipe와 Element version, parameter/schema hash, reasonCode, evidence hash,
deployment identity와 block/finality를 포함하되 성명, email, KYC 원문과 secret은
제외합니다.
판정 재현성을 얻는 대신 indexer, 보관과 접근 통제 운영이 필요합니다. 보관
기간과 운영 주체는 아직 정하지 않았습니다.
안전우선 긴급 교체 정책을 사용한다 — D-4, Q.6 파생
선택지는 정상 timelock을 유지한 새 버전 배포, Safe break-glass 즉시 활성화,
또는 같은 Element ID의 제자리 교체였습니다.
즉시 pause한 뒤 새 immutable Element/Recipe/Manifest를 배포하고, Safe 승인과
1일 timelock, 배포 후 검증을 거쳐 거래를 재개합니다. break-glass 우회 권한과
동일 ID 교체는 허용하지 않습니다.
Safe 탈취·오판이 즉시 compliance 완화로 이어지는 경로와 동일 ID가 서로 다른
코드를 의미하게 되는 감사 문제를 막습니다. 그 대가로 수정과 timelock 동안의
거래 중단을 감수합니다.
production은 exact Recipe version만 사용한다 — Q.7
latest는 편리하지만 높은 version 등록만으로 참조 대상이 즉시 바뀝니다.production은 exact
(recipeKey, version)만 사용하고latest는 UI·발견 용도로만허용합니다. 같은 정책 family의 심사된 후속 정책만 version을 올리고, 의미가
다른 정책은 새 key/id와 version 1을 사용합니다.
정책 재현성을 얻는 대신 CLI와 operator가 exact version을 관리해야 합니다.
PR #98의 MinimumTradeAmount Recipe도 기존 BUIDL-like recipe ID를 재사용하지
않아야 합니다.
구현을 병합 전 P0와 production 전 P1으로 나눈다 — Q.8
PR #98의 실제 안전성·호환성 문제는 병합 전에 처리합니다. 여기에는 새 Recipe
identity, Manifest retire 전 capability preflight, parameter 없는 profile의 legacy
Factory 경로, CLI와 Engine 판정 정렬, 회귀 테스트가 포함됩니다.
Element schema metadata, pending plan 조회, GIWA gas 검증, 나머지 정책값 migration,
감사 snapshot과 incident runbook은 production 전 P1으로 분리합니다. 검토 범위를
통제할 수 있지만, P0 완료만으로 production-ready라고 표시할 수는 없습니다.
공통 술어 정규화는 실제 schema 반복을 확인한 뒤 별도 ADR로 판단합니다.
BUIDL-like 500만 기준은 issuer/legal 승인 자료가 없으므로 실제 상품정책이 아닌
reference demo의 behavior lock으로만 유지합니다.
결정 필요
개발
개발은 Element별 parameter ABI, 단위, 범위와 최대 길이 초안을 작성해야 합니다.
GIWA 측정 후 한 개의 global hard cap을 둘지 chain별 cap을 둘지 비교하고,
현재 Element 저장값을 일괄 migration할지 단계적으로 옮길지 기술안을 제시해야
합니다.
공통 술어 정규화는 하지 않는 안, 반복되는 일부 유형만 표준화하는 안, 모든
Element를 범용 predicate로 바꾸는 안이 있습니다. 실제 반복과 gas·code 절감
효과를 측정한 뒤 결정해야 합니다.
리걸
리걸은 어떤 값이 자산별 허용·거부의 법적 의미를 갖는지 승인해야 합니다.
같은 숫자라도 최소 주문량, 최초 청약액, 거래 후 잔액은 의미가 다르므로 단위,
경계값과 매수·매도 적용 방향을 확정해야 합니다.
감사 snapshot의 필수 필드, 보관 기간, 접근 권한과 제출 형식도 정해야 합니다.
실제 BUIDL profile은 issuer 승인 자료를 근거로 금액의 의미, 통화/NAV, rounding,
oracle freshness와 잔액 조건을 확정해야 합니다. KYC/TA evidence의 필수성,
만료와 provider 장애 시 fail-closed 기준도 리걸 승인이 필요합니다.
그 외
그 외에는 제품, 운영, 보안, 조달/파트너와 issuer/asset manager의 결정을 묶습니다.
개발의 측정 결과와 리걸의 정책 경계를 받은 뒤 migration 대상과 출시 순서,
허용 downtime, indexer와 incident 운영, Safe signer/threshold와 key custody,
KYC/TA·storage vendor 및 실제 상품 승인 자료를 정해야 합니다.
PR #98에 미치는 영향
PR #98은 Manifest parameter 저장·hash·Engine 전달과 MinimumTradeAmount,
Factory·CLI·Toolkit 배선을 구현한 부분 구현입니다. 현재 리뷰에서 확인된 recipe
identity 충돌, retire 이전 capability 검증 부재, Factory 호환성, CLI와 Engine의
판정 불일치를 P0로 수정하고 재검토하기 전에는 병합하지 않습니다.
검증
git diff --check통과관련: #90, #97, #98