IPrivacy.singleProofBatchTransfer

singleProofBatchTransfer(
  PrivacySingleProofBatchTransferRequest request
) external returns (bool success)

프라이버시 프리컴파일(0x100000000000000000000000000000000000000b)에서 단일 증명 배치 전송을 실행합니다. 하나의 영지식 증명으로 nullifiers가 지정하는 1..N개의 입력 노트를 소비하고 outputs의 1..N개 출력 노트를 생성하므로, 단일 transfer를 반복 호출할 때보다 전송당 증명 비용이 크게 줄어듭니다. 입력·출력 개수는 각각 체인의 BatchJoinSplitV1MaxInputs / BatchJoinSplitV1MaxOutputs 상한을 넘을 수 없으며, 실효 발신자는 직접 호출자(msg.sender)입니다. 이 프리컴파일은 커스텀 오류 타입을 선언하지 않으므로 실패는 일반 문자열 revert로 전달됩니다.

파라미터

이름 타입 필수 설명
request PrivacySingleProofBatchTransferRequest 배치 페이로드입니다. 필드는 다음과 같습니다. proof(모든 입출력을 함께 증명하는 단일 ZK 증명), root(증명이 대상으로 삼은 Merkle 루트 스냅샷), nullifiers(노트의 nullifier bytes 배열, 중복이 없어야 하고 미소비 상태여야 합니다), outputs(commitment, ciphertext, viewTag, 노트별 공개 정책 필드, audit 공개 페이로드를 담는 PrivacySingleProofBatchTransferOutput 배열), auditKeyId / auditKeyEpoch / auditDisclosureTargetPubkey(audit 키 바인딩), expiresAtUnix(0이면 안 되고 블록 시간보다 반드시 커야 하며, 그렇지 않으면 호출이 revert됩니다).

반환값

타입: bool

성공 시 true를 반환합니다. 실패는 타입 지정 커스텀 오류가 아니라 일반 문자열 revert로 전달됩니다.

에러

코드 이름 설명
expiresAtUnix is required expiresAtUnix is required request.expiresAtUnix가 0이면 이 문자열로 revert됩니다. expiresAtUnix는 미래 unix 타임스탬프여야 하며, 0은 미지정으로 간주되어 증명 검증 이전에 거절됩니다.
single-proof batch transfer payload has expired single-proof batch transfer payload has expired 블록 시간이 이미 expiresAtUnix에 도달하면 이 문자열로 revert됩니다. 페이로드의 TTL이 지났으며, 새 증명과 만료 시각 없이는 재제출할 수 없습니다.
privacy single-proof batch input count must be in 1..%d privacy single-proof batch input count must be in 1..%d nullifiers가 비어있거나 BatchJoinSplitV1MaxInputs를 초과하면 이 문자열로 revert됩니다. 원문의 %d에는 실제 체인 설정 상한이 채워집니다.
privacy single-proof batch output count must be in 1..%d privacy single-proof batch output count must be in 1..%d outputs가 비어있거나 BatchJoinSplitV1MaxOutputs를 초과하면 이 문자열로 revert됩니다.
duplicate privacy single-proof batch nullifier duplicate privacy single-proof batch nullifier request.nullifiers에서 동일한 nullifier가 두 번 나타나면 이 문자열로 revert됩니다.
privacy single-proof batch nullifier already spent privacy single-proof batch nullifier already spent 제출한 nullifier 중 하나가 이전 프라이버시 호출에서 이미 소비된 경우 이 문자열로 revert됩니다.
duplicate privacy single-proof batch output commitment duplicate privacy single-proof batch output commitment request.outputs의 두 출력이 동일한 commitment을 가지면 이 문자열로 revert됩니다.
privacy single-proof batch output commitment already exists privacy single-proof batch output commitment already exists 출력의 commitment이 이미 온체인 commitment 인덱스에 존재하면 이 문자열로 revert됩니다.
not enough merkle tree capacity for privacy single-proof batch outputs: %w not enough merkle tree capacity for privacy single-proof batch outputs len(outputs)만큼의 새 commitment을 추가하면 Merkle 트리 용량을 초과하는 경우 이 문자열로 revert됩니다.
stateful privacy call global tx limit exceeded stateful privacy call global tx limit exceeded 블록당 stateful 프라이버시 호출 전역 한도가 이미 소진된 경우 이 문자열로 revert됩니다.
stateful privacy call per-effective-sender tx limit exceeded stateful privacy call per-effective-sender tx limit exceeded 블록당 실효 발신자별 stateful 프라이버시 호출 한도가 이 블록의 이전 호출들로 소진된 경우 이 문자열로 revert됩니다.

예제

viem으로 단일 증명 배치 전송 제출

단일 증명 방식은 검증 비용을 모든 입출력 쌍에 걸쳐 분산시킵니다. expiresAtUnix는 필수이며, 예상 포함 시점을 조금 넘긴 값으로 설정합니다. 페이로드가 이 시각 이후까지 mempool에 남아 있으면 호출이 revert되고 증명을 다시 생성해야 합니다.

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

const PRIVACY = "0x100000000000000000000000000000000000000b" as const;

const privacyAbi = [{
  type: "function",
  name: "singleProofBatchTransfer",
  stateMutability: "nonpayable",
  inputs: [{
    name: "request",
    type: "tuple",
    components: [
      { name: "proof",                       type: "bytes"   },
      { name: "root",                        type: "bytes"   },
      { name: "nullifiers",                  type: "bytes[]" },
      { name: "outputs",                     type: "tuple[]", components: [
        { name: "commitment",                 type: "bytes"  },
        { name: "ciphertext",                 type: "bytes"  },
        { name: "viewTag",                    type: "bytes"  },
        { name: "userPrivacyPolicy",          type: "uint32" },
        { name: "userDisclosureMode",         type: "uint8"  },
        { name: "userDisclosureDigest",       type: "bytes"  },
        { name: "userDisclosureTargetPubkey", type: "bytes"  },
        { name: "userDisclosurePayload",      type: "bytes"  },
        { name: "fullDisclosureDigest",       type: "bytes"  },
        { name: "auditDisclosurePayload",     type: "bytes"  },
        { name: "selfViewDisclosurePayload",  type: "bytes"  },
      ]},
      { name: "auditKeyId",                  type: "string"  },
      { name: "auditKeyEpoch",               type: "uint64"  },
      { name: "auditDisclosureTargetPubkey", type: "bytes"   },
      { name: "expiresAtUnix",               type: "uint64"  },
    ],
  }],
  outputs: [{ type: "bool" }],
}] as const;

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

// `request` is prepared by your off-chain prover; the fields below are
// placeholder shapes and must be replaced with real prover output.
const request = {
  proof:       "0x...",
  root:        "0x...",
  nullifiers:  ["0x...", "0x..."] as `0x${string}`[],
  outputs: [
    /* PrivacySingleProofBatchTransferOutput entries */
  ],
  auditKeyId:                  "audit-key-1",
  auditKeyEpoch:               1n,
  auditDisclosureTargetPubkey: "0x...",
  // TTL must be a future unix timestamp; a fresh prover run should set this.
  expiresAtUnix:               BigInt(Math.floor(Date.now() / 1000) + 300),
};

await wallet.writeContract({
  address:      PRIVACY,
  abi:          privacyAbi,
  functionName: "singleProofBatchTransfer",
  args:         [request],
});

문자열 revert 실패 디코드

이 프리컴파일에는 decodeErrorResult를 시도하지 마십시오. 커스텀 오류가 아닌 문자열 revert를 발행합니다. UX 분기 처리는 원문 reason 문자열을 부분 일치로 매칭합니다.

import { BaseError, ContractFunctionRevertedError } from "viem";

try {
  await wallet.writeContract({
    address:      PRIVACY,
    abi:          privacyAbi,
    functionName: "singleProofBatchTransfer",
    args:         [request],
  });
} catch (err) {
  if (err instanceof BaseError) {
    const revert = err.walk(e => e instanceof ContractFunctionRevertedError);
    if (revert instanceof ContractFunctionRevertedError) {
      // The privacy precompile declares no typed custom errors, so
      // `revert.reason` is a plain string such as:
      //   "privacy single-proof batch nullifier already spent"
      //   "single-proof batch transfer payload has expired"
      console.error("privacy revert:", revert.reason);
    }
  }
  throw err;
}
ESC
검색어를 입력하세요