IPrivacy.transfer

transfer(PrivacyTransferRequest request) external returns (bool success)

하나 이상의 셸디드 노트를 소비하고 Groth16 증명으로 새 노트를 생성합니다. msg.sender가 effective sender이며, PCL은 호출자를 기준으로 정책을 평가합니다. 실패는 IPrivacy에 선언된 타입 지정 커스텀 오류(요청 만료, nullifier/커밋먼트 충돌, Merkle 용량, 트랜잭션당 한도) 또는 IPrecompile에서 상속된 오류로 revert됩니다. PCL 정책 실패는 그 대신 IPcl의 PCL ReasonCode로 노출됩니다.

파라미터

이름 타입 필수 설명
request PrivacyTransferRequest 셸디드 transfer 페이로드입니다. 증명, Merkle 루트, nullifier들, 새 커밋먼트들, 암호문들, 뷰 태그들, 공개 필드, expiresAtUnix를 포함합니다. expiresAtUnix는 필수이며 현재 블록 시간보다 커야 합니다. 0이거나 과거이면 PrivacyRequestExpired(expiresAtUnix)로 revert됩니다.

반환값

타입: bool

성공 시 true를 반환합니다. 실패는 false 반환이 아니라 타입 지정 커스텀 오류로 revert됩니다.

에러

코드 이름 설명
PrivacyNonPayable PrivacyNonPayable msg.value가 0이 아닐 때 revert됩니다. value를 받는 메서드는 deposit뿐입니다. 페이로드는 메서드 이름입니다.
PrivacyRequestExpired PrivacyRequestExpired request.expiresAtUnix가 0이거나 이미 지났을 때 revert됩니다. 페이로드에는 unix 타임스탬프가 담깁니다.
PrivacyNullifierAlreadySpent PrivacyNullifierAlreadySpent 요청의 nullifier가 이미 온체인에 기록되어 있을 때 revert됩니다(이중 지출 시도).
PrivacyCommitmentAlreadyExists PrivacyCommitmentAlreadyExists 요청의 새 커밋먼트가 이미 Merkle 트리에 존재할 때 revert됩니다.
PrivacyMerkleCapacityExceeded PrivacyMerkleCapacityExceeded 새 커밋먼트를 추가하면 셸디드 풀 Merkle 트리 용량을 초과할 때 revert됩니다. 페이로드는 출력 개수입니다.
PrivacyTxLimitExceeded PrivacyTxLimitExceeded 현재 트랜잭션이 이미 너무 많은 stateful privacy 호출을 수행했을 때 revert됩니다(전역 한도).
PrivacySenderTxLimitExceeded PrivacySenderTxLimitExceeded effective sender가 이 트랜잭션에서 이미 너무 많은 stateful privacy 호출을 수행했을 때 revert됩니다. 페이로드는 (sender, limit)입니다.
InvalidNumberOfArgs InvalidNumberOfArgs IPrecompile에서 상속됩니다. ABI 인코딩된 호출이 정확히 하나의 인자를 담고 있지 않을 때 revert됩니다.
UnknownMethod UnknownMethod IPrecompile에서 상속됩니다. ABI selector가 프리컴파일의 어떤 함수와도 일치하지 않을 때 revert됩니다.

예제

직접 셸디드 transfer

PCL과 sender별 rate-limit 집계에서 msg.sender가 effective sender로 처리됩니다.

import { createWalletClient, http } 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"),
});

// `request` is prepared off-chain; expiresAtUnix must be in the future.
await wallet.writeContract({
  address: PRIVACY,
  abi: privacyAbi,
  functionName: "transfer",
  args: [request],
});

셸디드 풀 충돌 디코드

두 오류 모두 클라이언트의 노트 집합이 온체인 트리에 비해 오래되었다는 뜻입니다. 재시도 전에 갱신합니다.

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

try {
  await wallet.writeContract({
    address: PRIVACY,
    abi: privacyAbi,
    functionName: "transfer",
    args: [request],
  });
} catch (err: any) {
  if (!err?.data) throw err;
  const decoded = decodeErrorResult({ abi: privacyAbi, data: err.data });
  if (decoded.errorName === "PrivacyNullifierAlreadySpent") {
    // The user tried to spend a note that is already gone — refresh their note
    // set from the indexer and rebuild the proof.
    console.warn("note already spent — reload note set");
  } else if (decoded.errorName === "PrivacyMerkleCapacityExceeded") {
    const [count] = decoded.args as [bigint];
    console.warn(`shielded tree is full (${count} outputs requested)`);
  } else {
    throw err;
  }
}
ESC
검색어를 입력하세요