IPrivacy.deposit
deposit(
PrivacyDepositRequest request
) external payable returns (bool success) Escrows the caller's transparent OKRW (attached as msg.value) into the shielded pool and appends the note commitment from request to the Merkle tree. deposit is the only payable method on IPrivacy. The shielded amount is bounded by a 64-bit field, so a single deposit is capped at 18446744073709551615 base units (~18.446744073709551615 OKRW) — larger balances are held as multiple notes. Failures revert with typed custom errors on IPrivacy or inherited errors on IPrecompile.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
request | PrivacyDepositRequest | ✓ | The deposit payload: noteCommitment (the shielded output), encryptedNote (the ciphertext the recipient will decrypt), and proof (the deposit validity proof). |
Returns
bool Returns true on success. Failures revert with a typed custom error rather than returning false.
Errors
| Code | Name | Description |
|---|---|---|
InvalidAmount | InvalidAmount | Inherited from IPrecompile. Reverts when msg.value fails shielded-amount validation (zero, negative-in-unsigned-form, or exceeding the 64-bit shielded cap). Encoded as InvalidAmount(string amount) where the payload is the decimal string of the amount. |
InvalidAddress | InvalidAddress | Inherited from IPrecompile. Reverts when the caller address cannot be converted to a valid account address (usually the zero address). Encoded as InvalidAddress(string bad). |
PrivacyCommitmentAlreadyExists | PrivacyCommitmentAlreadyExists | Reverts when the noteCommitment already exists in the shielded-pool Merkle tree. |
PrivacyMerkleCapacityExceeded | PrivacyMerkleCapacityExceeded | Reverts when appending the deposit's commitment would exceed the Merkle tree capacity. |
InvalidNumberOfArgs | InvalidNumberOfArgs | Declared in the shared IPrecompile error set as InvalidNumberOfArgs(uint256 expected, uint256 got), but this function does not revert with it for a wrong argument count: calldata too short for the request reverts with ABISetupFailed, and bytes after the request are ignored. |
ABISetupFailed | ABISetupFailed | Inherited from IPrecompile as ABISetupFailed(string reason). Reverts when the calldata cannot be decoded against the precompile's ABI: an unknown 4-byte selector gives the reason no method with id: 0x… (usually a stale ABI), and calldata too short for the arguments gives the decoder's message, for example abi: cannot marshal in to go type: length insufficient 32 require 64. An unknown selector does not revert with UnknownMethod, although the precompile declares it. |
Examples
Deposit 15 OKRW into the shielded pool
Larger balances (e.g. 10,000,000 OKRW) are held as many notes — split the amount across many deposits, each below the 64-bit cap.
import { createWalletClient, http, parseEther } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { iPrivacyAbi } from "@maroo-chain/contracts/abi/precompiles/privacy/IPrivacy";
const PRIVACY = "0x100000000000000000000000000000000000000b" as const;
const wallet = createWalletClient({
account: privateKeyToAccount(process.env.USER_KEY as `0x${string}`),
transport: http("https://rpc-testnet.maroo.io"),
});
// Stays under the 64-bit shielded cap (~18.446... OKRW per deposit).
await wallet.writeContract({
address: PRIVACY,
abi: iPrivacyAbi,
functionName: "deposit",
args: [request],
value: parseEther("15"),
}); Handling the 64-bit shielded amount cap
The 64-bit shielded cap is enforced by the underlying ValidateShieldedAmount check, which now surfaces as InvalidAmount(string) after the shared-error refactor. Update any ABI fragment that previously declared it as InvalidAmount(uint256).
import { BaseError, ContractFunctionRevertedError, decodeErrorResult, parseEther } from "viem";
import { iPrivacyAbi } from "@maroo-chain/contracts/abi/precompiles/privacy/IPrivacy";
try {
await wallet.writeContract({
address: PRIVACY,
abi: iPrivacyAbi,
functionName: "deposit",
args: [request],
value: parseEther("20"), // above the 64-bit shielded cap — will revert
});
} catch (err) {
// viem keeps the revert data on the ContractFunctionRevertedError in the cause chain, not on err.
const revert = err instanceof BaseError ? err.walk((e) => e instanceof ContractFunctionRevertedError) : null;
if (!(revert instanceof ContractFunctionRevertedError) || !revert.raw) throw err;
const decoded = decodeErrorResult({ abi: iPrivacyAbi, data: revert.raw });
if (decoded.errorName === "InvalidAmount") {
const [amount] = decoded.args as [string];
console.warn(`deposit amount ${amount} exceeds 64-bit shielded cap — split across multiple notes`);
} else {
throw err;
}
}