프라이버시 프리컴파일

component privacy

0x100000000000000000000000000000000000000b의 은닉 풀 OKRW 프리컴파일입니다. Groth16 증명 아래에서 노트를 예치·전송·인출하며, 모든 실패 모드에 대해 타입 지정 revert 데이터를 반환합니다.

0x100000000000000000000000000000000000000b의 프라이버시 프리컴파일은 OKRW 은닉 풀을 구현합니다. 호출자는 투명 OKRW를 deposit하여 노트를 커밋하거나, Groth16 증명 아래에서 다른 수신자에게 노트를 transfer하거나, 노트를 투명 EOA로 withdraw할 수 있습니다. 각 메서드에는 EIP-712 기반 *WithAuthorization 릴레이 변형과 배치 변형이 함께 제공됩니다. 상태를 변경하는 모든 호출은 프리컴파일 경계에서 PCL 정책 평가를 통과하므로, 은닉 흐름도 투명 흐름과 동일한 컴플라이언스 규칙을 따릅니다. 실패는 이제 IPrivacy에 선언된 타입 지정 커스텀 오류로 revert됩니다. IPrecompile에서 상속되는 공통 오류, 요청 수명주기 계열(PrivacyNonPayable, PrivacyRequestExpired, PrivacyBatchSizeOutOfRange, PrivacyNativeDenomMismatch), 인증 계열(PrivacyInvalidAuthorizationField, PrivacyAuthorizationExpired, PrivacyAuthorizationNonceUsed, PrivacyAuthorizationSignerMismatch, PrivacyAuthorizationRejected, PrivacyInvalidAuthorizationMagic), 은닉 상태 계열(PrivacyDuplicateNullifier, PrivacyNullifierAlreadySpent, PrivacyDuplicateCommitment, PrivacyCommitmentAlreadyExists, PrivacyMerkleCapacityExceeded, PrivacyTxLimitExceeded, PrivacySenderTxLimitExceeded)이 포함됩니다.

아키텍처

flowchart LR
  User["Wallet / dApp"] -->|"deposit / transfer / withdraw"| Priv["IPrivacy<br/>0x…000b"]
  User -->|"*WithAuthorization<br/>(relayed)"| Relayer["Relayer"]
  Relayer -->|"executor tx"| Priv
  Priv -->|"preflight"| PCL["IPcl"]
  Priv -->|"revert with typed IPrivacy error"| User
  classDef evm fill:#0096AA,stroke:#0096AA,color:#fff;
  classDef precompile fill:#FF8C50,stroke:#FF8C50,color:#fff;
  class User,Relayer evm;
  class Priv,PCL precompile;

상태를 변경하는 모든 호출은 PCL 사전 검사를 통과한 뒤 은닉 상태를 커밋하거나 타입 지정 IPrivacy 오류로 revert합니다.

노출되는 표면

상태를 변경하는 아홉 메서드가 세 쌍과 배치로 구성되어 있습니다.

형태직접 호출릴레이 변형
값 유입deposit (payable)
노트 간 이동transfertransferWithAuthorization
값 유출withdrawwithdrawWithAuthorization
배치batchTransfer, singleProofBatchTransferbatchTransferWithAuthorization, singleProofBatchTransferWithAuthorization

payabledeposit뿐입니다. 다른 메서드는 첨부된 값이 있으면 PrivacyNonPayable(methodName)으로 거절합니다. 모든 은닉 금액은 64비트이므로, 한 번의 연산으로 옮길 수 있는 최대치는 18.446744073709551615 OKRW입니다. 더 큰 잔액은 여러 노트로 나누어 보관합니다.

요청 수명주기 오류

요청 자체가 위반하는 주변 조건입니다.

  • PrivacyNonPayable(string methodName) — payable이 아닌 프라이버시 메서드에 msg.value를 첨부했습니다.
  • PrivacyRequestExpired(uint64 expiresAtUnix) — 요청의 expiresAtUnix가 이미 지났습니다. mempool 지연을 감안해 몇 블록 뒤로 설정합니다.
  • PrivacyBatchSizeOutOfRange(uint256 count, uint256 max)batchTransfer / singleProofBatchTransfer가 허용 크기를 벗어났습니다.
  • PrivacyNativeDenomMismatch(string got, string expected) — 요청의 denom이 체인의 네이티브 denom(aokrw)이 아닙니다.


공유 IPrecompile 디코드 테이블에 아래 네 selector를 함께 넣어 디코드합니다.
import { decodeErrorResult } from "viem";

const privacyLifecycleAbi = [
  { type: "error", name: "PrivacyNonPayable",          inputs: [{ name: "methodName",    type: "string" }] },
  { type: "error", name: "PrivacyRequestExpired",     inputs: [{ name: "expiresAtUnix", type: "uint64" }] },
  { type: "error", name: "PrivacyBatchSizeOutOfRange",inputs: [{ name: "count", type: "uint256" }, { name: "max", type: "uint256" }] },
  { type: "error", name: "PrivacyNativeDenomMismatch",inputs: [{ name: "got",  type: "string" }, { name: "expected", type: "string" }] },
] as const;

try {
  await client.writeContract({ /* 프라이버시 호출 */ });
} catch (err: any) {
  if (err?.data) {
    const decoded = decodeErrorResult({ abi: privacyLifecycleAbi, data: err.data });
    console.error(decoded.errorName, decoded.args);
  }
}

인증 오류 — *WithAuthorization 릴레이 경로

릴레이 변형(transferWithAuthorization, withdrawWithAuthorization, singleProofBatchTransferWithAuthorization, batchTransferWithAuthorization)은 실행자와 분리된 EIP-712 서명을 받습니다. 서명 페이로드는 privacy-authorization-eip712-domain에서 확인합니다. 와이어 struct는 6개 필드이지만 서명 대상 typeHash는 11개 필드로 다릅니다.

  • PrivacyInvalidAuthorizationField(string field) — 필수 필드가 누락되었거나 형식이 잘못되었습니다(예: deadline 미설정, selector 길이가 4바이트가 아님).
  • PrivacyAuthorizationExpired(uint64 deadline)deadline이 이미 지났습니다.
  • PrivacyAuthorizationNonceUsed(address sender, uint256 nonce) — effective-sender nonce가 이미 소모되었습니다.
  • PrivacyAuthorizationSignerMismatch(address expected, address got) — 복원된 서명자가 effective sender와 일치하지 않습니다.
  • PrivacyAuthorizationRejected(uint8 authorizationKind) — effective sender가 컨트랙트이며 그 ERC-1271 검증자가 서명을 거절했습니다.
  • PrivacyInvalidAuthorizationMagic(bytes4 magic) — ERC-1271 검증자가 인식되지 않는 매직 값을 반환했습니다.

은닉 상태 오류

은닉 상태 기계 자체에서 발생하는 실패입니다.

  • PrivacyDuplicateNullifier() — 같은 nullifier가 한 요청에 두 번 등장합니다.
  • PrivacyNullifierAlreadySpent() — 해당 nullifier가 이미 온체인에 기록되어 있습니다(이중 지출 시도).
  • PrivacyDuplicateCommitment() — 같은 출력 커밋먼트가 한 요청에 두 번 등장합니다.
  • PrivacyCommitmentAlreadyExists() — 출력 커밋먼트가 이미 Merkle 트리에 존재합니다.
  • PrivacyMerkleCapacityExceeded(uint256 count) — 요청의 커밋먼트를 추가하면 트리 용량을 초과합니다.
  • PrivacyTxLimitExceeded(uint256 limit) — 블록당 체인 전역 프라이버시 트랜잭션 한도를 초과했습니다.
  • PrivacySenderTxLimitExceeded(address sender, uint256 limit) — 발신자별 프라이버시 트랜잭션 한도를 초과했습니다.


대부분의 경우 클라이언트가 노트 집합을 다시 스캔해 재시도해야 한다는 신호입니다. 중복 nullifier는 보통 풀에 대한 오래된 뷰를 의미합니다.

디코드 불가능한 실패

일부 검사는 타입 인코딩 이전에 실행되어 평문 문자열 revert로 노출됩니다. decodeErrorResult가 아니라 문자열로 디코드합니다. 구체 예시로 "authorization deadline is required", "authorization effective sender and executor are required", "authorization selectors must be 4 bytes", "expiresAtUnix overflows int64", "invalid batchId", "duplicate privacy batchId in EVM transaction", "prepared privacy deposit denom %q does not match runtime native denom %q"가 있습니다. err.data가 있으면 타입 디코더로, 없으면 상위 오류 메시지에서 문자열 이유를 읽는 방식으로 분기합니다.
ESC
검색어를 입력하세요