IPrivacy.withdrawWithAuthorization
withdrawWithAuthorization(
PrivacyWithdrawRequest request,
PrivacyActionAuthorization authorization
) external returns (bool) Withdraws funds from the shielded pool back to a transparent EVM recipient on behalf of an effectiveSender who signed an EIP-712 authorization. The executor (typically a relayer) submits the transaction; the precompile verifies the signature, enforces nonce / deadline replay protection, then performs the same nullifier-consuming withdraw state transition as the direct withdraw method. The amount field is a coin string parsed by the chain (e.g. "10000000000000000000atokrw" for 10 OKRW).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
request | PrivacyWithdrawRequest | ✓ | The shielded withdraw payload: proof, root, nullifier, amount (coin string, e.g. "10000000000000000000atokrw"), recipient (transparent EVM address), chainId, and expiresAtUnix. amount must fit the 64-bit shielded amount field — at most 2^64-1 atokrw = 18.446744073709551615 OKRW per operation; over that, request validation rejects it before the proof is verified or the nullifier is consumed, and an EVM caller sees a bare SDKInvalidRequest() — the node-side reason (withdraw amount exceeds 64-bit shielded amount limit) is not in the revert data. The full failure list is on IPrivacy.withdraw; this method adds only the authorization checks. |
authorization | PrivacyActionAuthorization | ✓ | EIP-712 signed authorization from effectiveSender. executor must equal msg.sender; see privacy-authorization-eip712-domain for the canonical domain. |
Returns
Type:
bool Returns true on success. Failures revert.
Examples
Relayed withdraw of 10 OKRW
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { iPrivacyAbi } from "@maroo-chain/contracts/abi/precompiles/privacy/IPrivacy";
const PRIVACY = "0x100000000000000000000000000000000000000b" as const;
const relayer = createWalletClient({
account: privateKeyToAccount(process.env.RELAYER_KEY as `0x${string}`),
transport: http("https://rpc-testnet.maroo.io"),
});
// The proof, this request and the owner's EIP-712 signature are made together, off-chain: the proof binds
// the amount, recipient and expiresAtUnix, and the signature covers its deadline and the hash of this
// request. Pass the values they were made for — a new expiresAtUnix needs a new proof and a new signature.
const withdrawRequest = {
proof: proofBytes,
root: merkleRoot,
nullifier: nullifierBytes,
amount: "10000000000000000000atokrw", // 10 OKRW
recipient: "0x1111111111111111111111111111111111111111" as const, // TODO: replace before production
// The chain's Cosmos chain-id, EXACTLY — read it from the node:
// GET /cosmos/base/tendermint/v1beta1/node_info → default_node_info.network.
// A mismatch reverts with a bare `SDKInvalidRequest()` that does not say which
// value was expected, so check it before you sign.
chainId: process.env.MAROO_COSMOS_CHAIN_ID as string,
expiresAtUnix: provedExpiresAtUnix, // the deadline the proof was generated for
};
await relayer.writeContract({
address: PRIVACY,
abi: iPrivacyAbi,
functionName: "withdrawWithAuthorization",
args: [
withdrawRequest,
{
effectiveSender,
executor: relayer.account.address,
nonce,
deadline: signedDeadline, // the deadline the owner signed
authorizationKind: 1, // AUTH_KIND_EOA — the SIGNATURE SCHEME, not the action.
// 2 = ERC-1271 contract signature, 3 = EIP-7702 delegated EOA.
signature: eip712Signature,
},
],
});