IPrivacy.singleProofBatchTransferWithAuthorization

singleProofBatchTransferWithAuthorization(
  PrivacySingleProofBatchTransferRequest request,
  PrivacyActionAuthorization authorization
) external returns (bool success)

Meta-transaction variant of singleProofBatchTransfer: a relayer submits the batch on behalf of authorization.effectiveSender, who signed an off-chain authorization binding the request hash to a specific executor, nonce, and deadline. Supports EOA signatures, ERC-1271 smart-account signatures, and EIP-7702 delegated-EOA signatures, chosen via authorization.authorizationKind. The request-hash domain is dedicated to the single-proof batch method — it will not collide with authorizations for other privacy calls. All failure modes surface as plain string reverts; no typed custom errors are declared on this precompile.

Parameters

Name Type Required Description
request PrivacySingleProofBatchTransferRequest Same batch payload as singleProofBatchTransfer. Its hash — computed over the method ID and the ABI-encoded request tuple — is bound into the authorization signature.
authorization PrivacyActionAuthorization Off-chain authorization. Fields: effectiveSender (the account the policy engine treats as the actual sender), executor (must equal msg.sender — the relayer address), nonce (unique per effectiveSender; replay-protected), deadline (unix seconds; must be in the future), authorizationKind (0=EOA, 1=ERC-1271, 2=EIP-7702; other values revert), and signature (bytes; for EOA a 65-byte (r, s, v) blob).

Returns

Type: bool

Returns true on success. Failures revert with a plain string reason.

Errors

Code Name Description
privacy authorization effectiveSender is required privacy authorization effectiveSender is required String revert when authorization.effectiveSender is the zero address.
privacy authorization executor is required privacy authorization executor is required String revert when authorization.executor is the zero address.
privacy authorization executor mismatch privacy authorization executor mismatch String revert when msg.sender does not equal authorization.executor.
privacy authorization deadline is required privacy authorization deadline is required String revert when authorization.deadline is zero.
privacy authorization expired privacy authorization expired String revert when the block time has passed authorization.deadline.
privacy authorization nonce already used privacy authorization nonce already used String revert when authorization.nonce has already been consumed by a prior privacy call for the same effectiveSender.
unsupported privacy authorization kind %d unsupported privacy authorization kind %d String revert when authorizationKind is not one of the supported values (0 EOA, 1 ERC-1271, 2 EIP-7702).
privacy EOA authorization signer mismatch privacy EOA authorization signer mismatch String revert when the recovered EOA signer does not match authorization.effectiveSender.
privacy EOA authorization signature must be 65 bytes privacy EOA authorization signature must be 65 bytes String revert when the EOA signature blob length is not 65 bytes.
privacy ERC-1271 authorization rejected: %w privacy ERC-1271 authorization rejected String revert when an ERC-1271 smart-account signature check fails on effectiveSender.
single-proof batch transfer payload has expired single-proof batch transfer payload has expired String revert when the block time has already reached request.expiresAtUnix.
privacy single-proof batch nullifier already spent privacy single-proof batch nullifier already spent String revert when one of the supplied nullifiers has already been consumed by a prior privacy call.
privacy single-proof batch output commitment already exists privacy single-proof batch output commitment already exists String revert when an output's commitment is already present in the on-chain commitment index.

Examples

Relayer submits an authorized single-proof batch

The relayer's own address is checked against authorization.executor; any mismatch reverts before the proof is evaluated. Pin the nonce off-chain (per-effectiveSender monotonic counter is fine).

import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const PRIVACY = "0x100000000000000000000000000000000000000b" as const;

// ABI snippet — reuse the `PrivacySingleProofBatchTransferRequest` shape
// documented on `contract-privacy-single-proof-batch-transfer`.
const privacyAbi = [{
  type: "function",
  name: "singleProofBatchTransferWithAuthorization",
  stateMutability: "nonpayable",
  inputs: [
    { name: "request",       type: "tuple", components: [ /* … */ ] },
    { name: "authorization", type: "tuple", components: [
      { name: "effectiveSender",   type: "address" },
      { name: "executor",          type: "address" },
      { name: "nonce",             type: "uint256" },
      { name: "deadline",          type: "uint64"  },
      { name: "authorizationKind", type: "uint8"   },
      { name: "signature",         type: "bytes"   },
    ]},
  ],
  outputs: [{ type: "bool" }],
}] as const;

// The relayer's key. Must equal `authorization.executor`.
// TODO: replace with the real relayer address before production.
const relayer = createWalletClient({
  account: privateKeyToAccount(process.env.RELAYER_KEY as `0x${string}`),
  transport: http("https://rpc-testnet.maroo.io"),
});

// `request` and `authorization` come from the effective sender's wallet.
// `authorization.signature` is over the EIP-712 domain documented on
// `privacy-authorization-eip712-domain`, using the single-proof batch
// request-hash.
await relayer.writeContract({
  address:      PRIVACY,
  abi:          privacyAbi,
  functionName: "singleProofBatchTransferWithAuthorization",
  args:         [request, authorization],
});

Handling authorization rejections

The authorization surface produces string reverts only. Branch on revert.reason substrings for UX; never call decodeErrorResult here.

import { BaseError, ContractFunctionRevertedError } from "viem";

try {
  await relayer.writeContract({
    address:      PRIVACY,
    abi:          privacyAbi,
    functionName: "singleProofBatchTransferWithAuthorization",
    args:         [request, authorization],
  });
} catch (err) {
  if (err instanceof BaseError) {
    const revert = err.walk(e => e instanceof ContractFunctionRevertedError);
    if (revert instanceof ContractFunctionRevertedError) {
      // Match on the verbatim reason substring — the privacy precompile
      // does not use typed custom errors.
      const r = revert.reason ?? "";
      if (r.includes("privacy authorization expired")) {
        // ask the effective sender to re-sign with a later deadline
      } else if (r.includes("privacy authorization nonce already used")) {
        // bump the nonce and re-sign
      } else if (r.includes("privacy authorization executor mismatch")) {
        // the signature was bound to a different relayer
      }
    }
  }
  throw err;
}
ESC
Type to search