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,
    },
  ],
});
ESC
Type to search