IPrivacy.batchTransfer

batchTransfer(
  bytes32 batchId,
  PrivacyTransferRequest[] requests
) external returns (bool success)

여러 개의 독립적으로 증명된 셸디드 transfer를 단일 트랜잭션 내에서 원자적으로 적용하며, 모두 batchId로 묶입니다. 각 항목은 배치 전체를 기준으로 중복 nullifier, 중복 커밋먼트, Merkle 용량이 사전 점검됩니다. 어느 하나라도 실패하면 호출 전체가 revert됩니다. 실패는 IPrivacy의 타입 지정 커스텀 오류 또는 IPrecompile의 상속 오류로 노출됩니다.

파라미터

이름 타입 필수 설명
batchId bytes32 호출자가 정하는 배치 식별자입니다. 0이 아니어야 하며 트랜잭션 내에서 유일해야 합니다. 각 배치 항목 이벤트와 로그가 이 값을 담아 오프체인 인덱서가 그룹화할 수 있습니다.
requests PrivacyTransferRequest[] 배치 항목들입니다. 길이는 1..MaxPrivacyMultiProofBatchItems 범위여야 하며, 비어 있거나 초과하면 PrivacyBatchSizeOutOfRange(count, max)로 revert됩니다. 모든 nullifier와 모든 새 커밋먼트는 배치 전체에서 유일해야 하고 이미 온체인에 기록되어 있어서는 안 됩니다.

반환값

타입: bool

모든 항목이 커밋되면 true를 반환합니다. 어떤 실패든 배치 전체가 revert됩니다.

에러

코드 이름 설명
PrivacyBatchSizeOutOfRange PrivacyBatchSizeOutOfRange requests가 비어 있거나 프로토콜 최대치를 초과할 때 revert됩니다. 페이로드는 (count, max)입니다.
PrivacyDuplicateNullifier PrivacyDuplicateNullifier 같은 nullifier가 배치의 여러 항목에 나타날 때 revert됩니다.
PrivacyNullifierAlreadySpent PrivacyNullifierAlreadySpent 배치의 nullifier 중 하나라도 이미 온체인에 기록되어 있을 때 revert됩니다.
PrivacyDuplicateCommitment PrivacyDuplicateCommitment 같은 새 커밋먼트가 배치의 여러 항목에 나타날 때 revert됩니다.
PrivacyCommitmentAlreadyExists PrivacyCommitmentAlreadyExists 배치의 새 커밋먼트 중 하나라도 이미 Merkle 트리에 존재할 때 revert됩니다.
PrivacyMerkleCapacityExceeded PrivacyMerkleCapacityExceeded 배치의 출력을 추가하면 셸디드 풀 Merkle 트리 용량을 초과할 때 revert됩니다.
PrivacyRequestExpired PrivacyRequestExpired 어떤 항목의 expiresAtUnix가 0이거나 이미 지났을 때 revert됩니다.
PrivacyTxLimitExceeded PrivacyTxLimitExceeded 트랜잭션이 이미 전역 stateful-privacy 호출 한도를 초과했을 때 revert됩니다.
InvalidNumberOfArgs InvalidNumberOfArgs IPrecompile에서 상속됩니다. 호출이 정확히 두 개의 인자를 담고 있지 않을 때 revert됩니다.

예제

다섯 개의 셸디드 transfer 묶기

5개 항목이 각각 독립적으로 증명되지만 함께 커밋되거나 함께 revert됩니다. 트랜잭션마다 새 batchId를 사용해 PrivacyBatchTransferItem 이벤트가 깔끔하게 묶이도록 합니다.

import { createWalletClient, http, keccak256, toHex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { privacyAbi } from "@maroo-chain/contracts/abi/IPrivacy";

const PRIVACY = "0x100000000000000000000000000000000000000b" as const;

const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.SENDER_KEY as `0x${string}`),
  transport: http("https://rpc-testnet.maroo.io"),
});

const batchId = keccak256(toHex(`payroll-${Date.now()}`));
await wallet.writeContract({
  address: PRIVACY,
  abi: privacyAbi,
  functionName: "batchTransfer",
  args: [batchId, requests], // requests.length in 1..MaxPrivacyMultiProofBatchItems
});

어떤 항목이 배치를 실패시켰는지 진단

배치 preflight 오류는 형태 수준(중복 제거, 용량)입니다. 실패한 한 항목이 배치 전체를 오염시킵니다. 필요하면 배치를 분할해 재시도하여 항목을 격리합니다.

import { decodeErrorResult } from "viem";
import { privacyAbi } from "@maroo-chain/contracts/abi/IPrivacy";

try {
  await wallet.writeContract({
    address: PRIVACY,
    abi: privacyAbi,
    functionName: "batchTransfer",
    args: [batchId, requests],
  });
} catch (err: any) {
  if (!err?.data) throw err;
  const decoded = decodeErrorResult({ abi: privacyAbi, data: err.data });
  // The typed error identifies WHICH invariant failed. Recompute preflight
  // client-side (dedupe nullifiers/commitments, refresh note set) and retry.
  console.warn("batch preflight failed:", decoded.errorName, decoded.args);
}
ESC
검색어를 입력하세요