Privacy Precompile

component privacy

Shielded OKRW transfers via a policy-aware precompile at 0x1000…000b. Deposits are payable; withdrawals settle to a public recipient; transfers stay inside the pool.

The Privacy precompile at 0x100000000000000000000000000000000000000b exposes shielded OKRW operations — deposit, transfer, withdraw, their authorization variants, and two batch variants — as an EVM-callable surface wrapped by the policy-aware precompile framework. Deposits are payable and take their amount from native msg.value in aokrw; the request struct itself carries only the note commitment, encrypted note, and ZK proof. Every mutating call exposes exactly one contract-scoped PolicyOperation that PCL evaluates before and after execution, so contract policies (denylists, periodic caps) apply uniformly to shielded flows.

Architecture

flowchart LR
    User[User dApp]:::evm
    Relayer[Relayer / Executor]:::evm
    Privacy[Privacy Precompile<br/>0x1000…000b]:::precompile
    Recipient[Transparent Recipient]:::evm

    User -- deposit / transfer / withdraw --> Privacy
    User -- EIP-712 signed intent --> Relayer
    Relayer -- ...WithAuthorization --> Privacy
    Privacy -- withdraw payout --> Recipient

    classDef evm fill:#0096AA,stroke:#0096AA,color:#fff;
    classDef precompile fill:#FF8C50,stroke:#FF8C50,color:#fff;

Direct callers hit the Privacy precompile from their own wallet; delegated callers sign an EIP-712 authorization off-chain and let a relayer submit the `…WithAuthorization` variant. Withdrawals settle to a transparent EVM recipient.

Method surface

The interface exposes the following mutating methods and no view methods:

MethodPayablePurpose
deposityesShield native OKRW; amount comes from msg.value.
transfernoMove shielded notes inside the pool.
withdrawnoUnshield to a public recipient.
transferWithAuthorizationnoSame as transfer, executed by a delegate under a signed authorization.
withdrawWithAuthorizationnoSame as withdraw, delegated.
batchTransfernoMultiple independent transfers under one batch id.
batchTransferWithAuthorizationnoDelegated batch transfer.
singleProofBatchTransfernoOne aggregated ZK proof covering many inputs/outputs.
singleProofBatchTransferWithAuthorizationnoDelegated single-proof batch.

There is no depositWithAuthorization. Deposits require the operator (msg.sender) to be the effective sender, so the depositor's own signature secures the operation directly.

Deposit amount lives in msg.value

The request struct passed to deposit is { bytes noteCommitment; bytes encryptedNote; bytes proof; } — no amount field. The deposit amount is derived from msg.value under the runtime native denom (aokrw). The PrivacyDeposit event still records the amount as a Cosmos-coin-formatted string ("10000000000000000000000000aokrw" for 10,000,000 OKRW) so downstream indexers see a canonical value.
// Shield 10,000,000 OKRW.
PRIVACY.deposit{value: 10_000_000 ether}(PrivacyDepositRequest({
    noteCommitment: commitment,
    encryptedNote:  encNote,
    proof:          zkProof
}));

Policy-aware wrapping

The precompile does not implement vm.PrecompiledContract directly. It is composed of a raw executor plus the policy-aware wrapper described in privacy-policy-aware-precompile. The wrapper takes the single PolicyOperation the executor prepares for each call and drives PCL through evaluate-before → execute → evaluate-after → record. A shielded transfer's hidden amount is modeled with value = 0 in that operation so identity and denylist policies still run without recording unverifiable periodic volume; a public deposit carries the true msg.value and does count toward volume caps.
ESC
Type to search