IPrivacy.transfer

transfer(PrivacyTransferRequest request) external returns (bool success)

은닉 전송을 실행합니다. 하나 이상의 nullifier를 소비하고 새 commitment를 머클 트리에 추가하며, 암호문·view tag·공개 페이로드를 기록합니다. PrivacyTransferRequest는 필수 필드 expiresAtUnix를 포함하며, 값이 0이거나 int64를 초과하거나 현재 블록 시간이 해당 시각 이후이면 일반 문자열 revert로 거절됩니다. 실패는 커스텀 오류 타입이 아니라 문자열 revert로 반환되므로(IPrivacy는 error 타입을 선언하지 않습니다), decodeErrorResult로 디코드할 수 없고 문자열을 그대로 확인해야 합니다.

파라미터

이름 타입 필수 설명
request PrivacyTransferRequest 은닉 전송 요청입니다. 전체 구조는 IPrivacy.sol을 참고합니다. 주요 필드로 proof, root, nullifiers, newCommitments, cipherTexts, viewTags, 공개 관련 필드가 있으며, 필수 필드 expiresAtUnix(유닉스 초 단위, 현재 블록 시간보다 크고 int64 범위 안이어야 합니다)를 포함합니다.

반환값

타입: bool

성공 시 true를 반환합니다. 실패는 일반 문자열 revert로 처리됩니다.

에러

코드 이름 설명
expiresAtUnix is required expiresAtUnix is required 문자열 revert입니다(커스텀 오류 타입이 아닙니다). expiresAtUnix가 0일 때 반환됩니다. IPrivacy는 error 타입을 선언하지 않으므로 revert reason이 이 문자열 그대로 반환되며, 클라이언트는 문자열로 판별해야 합니다. decodeErrorResult로는 디코드할 수 없습니다.
expiresAtUnix overflows int64 expiresAtUnix overflows int64 문자열 revert입니다. expiresAtUnix가 int64 범위를 초과할 때 반환됩니다.
transfer payload has expired transfer payload has expired 문자열 revert입니다. 현재 블록 시간이 expiresAtUnix 이상일 때 반환됩니다.

예제

만료 시각을 지정해 전송 요청 구성

expiresAtUnix는 이제 필수 필드입니다. 몇 분 뒤 시각으로 설정하면 트랜잭션이 mempool에 오래 머무를 때 오래된 페이로드가 재사용되는 것을 방지할 수 있습니다.

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

const PRIVACY = "0x100000000000000000000000000000000000000b" as const;

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

// Expire 5 minutes into the future. Never send 0 or a past timestamp —
// the precompile now rejects both with a plain string revert.
const nowSec = Math.floor(Date.now() / 1000);
const expiresAtUnix = BigInt(nowSec + 300);

const request = {
  proof:                       "0x...",
  root:                        "0x...",
  nullifiers:                  ["0x..."],
  newCommitments:              ["0x..."],
  cipherTexts:                 ["0x..."],
  viewTags:                    ["0x..."],
  userPrivacyPolicy:           0,
  userDisclosureDigest:        "0x",
  userDisclosureMode:          0,
  userDisclosureTargetPubkey:  "0x",
  userDisclosurePayload:       "0x",
  auditDisclosureDigest:       "0x",
  auditDisclosureTargetPubkey: "0x",
  auditDisclosurePayload:      "0x",
  selfViewDisclosureDigest:    "0x",
  selfViewDisclosurePayload:   "0x",
  expiresAtUnix,
} as const;

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

클라이언트에서 만료 거절 처리

IPrivacy가 커스텀 오류 타입을 선언하지 않으므로, 만료 거절은 revert reason 문자열을 그대로 비교해서 판별해야 합니다. decodeErrorResult로는 디코드할 수 없습니다.

try {
  await wallet.writeContract({
    address: PRIVACY,
    abi: privacyAbi,
    functionName: "transfer",
    args: [request],
  });
} catch (err: any) {
  // IPrivacy has no typed errors — the reason arrives as a plain string.
  const reason: string = err?.shortMessage || err?.message || "";
  if (reason.includes("transfer payload has expired")) {
    // Re-sign the payload with a fresh expiresAtUnix and retry.
  } else if (reason.includes("expiresAtUnix is required")) {
    // Programmer error: caller forgot to set expiresAtUnix.
  } else {
    throw err;
  }
}
ESC
검색어를 입력하세요