For the complete documentation index, see llms.txt. This page is also available as Markdown.

3.3.x

confidentialTransferAndCall, automatic pending-unshield recovery, and typed decryption error causes.

This page covers the 3.3.x line.

3.3.0

Released 2026-07-08.

This release adds a one-transaction "transfer and notify" primitive for ERC-7984 tokens, moves interrupted-unshield recovery fully inside the SDK, and gives decryption failures typed causes you can branch on. There are no breaking changes — every 3.1.x/3.2.x app upgrades cleanly.

Encrypted transfer with a receiver hook

Token.confidentialTransferAndCall() performs an encrypted transfer and invokes the recipient's ERC-7984 receiver hook (onConfidentialTransferReceived) in a single transaction. Use it when the recipient is a contract that needs to react to the transfer — for example a vault that credits a deposit the moment tokens arrive.

The amount is encrypted client-side for you. The data argument is an opaque payload the SDK forwards verbatim to the receiver hook — you encode and interpret it; the SDK never touches it.

// Transfer 1000 tokens to a vault contract and trigger its deposit hook in one tx.
const { txHash } = await token.confidentialTransferAndCall(
  "0xVaultContract",
  1000n,
  "0xabcd", // caller-encoded payload forwarded to onConfidentialTransferReceived
);

Balance validation, chain-alignment checks, and error handling match confidentialTransfer: the SDK reads your confidential balance first and throws InsufficientConfidentialBalanceError before sending anything if it is too low. Pass { skipBalanceCheck: true } to bypass the check for wallets that cannot produce EIP-712 signatures.

Automatic pending-unshield recovery

Unshielding is a two-phase flow — an unwrap transaction, then a finalize transaction after the decryption proof arrives. If the user closes the tab in between, the first transaction is on-chain but the withdrawal is unfinished.

The SDK now persists the pending unwrap automatically when phase one is submitted and clears it once finalization confirms. You no longer wire up any storage helpers yourself — you only detect and resume on the next load:

getPendingUnshield() returns the unwrap transaction hash of an interrupted unshield, or null. resumeUnshield() polls for the proof, submits the finalize transaction, and clears the persisted state on success.

In React, the same lifecycle is exposed through usePendingUnshield and useResumeUnshield.

Resume is intentionally caller-driven: surface a "resume withdrawal" prompt rather than finalizing automatically on load, so you never trigger a wallet transaction the user did not initiate. See Unshield tokens for the full flow.

Typed decryption error causes

Decryption can fail for reasons that call for very different responses — some are terminal, others are worth retrying. The SDK now distinguishes them with dedicated error subclasses so you can branch correctly instead of parsing messages:

Error
Code
Meaning
Retry?

NotEntitledError

NOT_ENTITLED

The account is not authorized by the on-chain ACL to decrypt this value

No — wait for a grant

RpcRateLimitError

RPC_RATE_LIMITED

Your RPC provider rate-limited an on-chain read (HTTP 429 / JSON-RPC -32005)

Yes

Relayer back-pressure surfaces the same way — as a typed, retryable cause rather than an opaque failure. Route them with matchZamaError:

See Handle errors for the full error hierarchy.

Reliability improvements

  • Self-healing Node worker timeouts. The Node relayer's worker timeouts are now configurable and diagnosable, and the pool recovers on its own from a stalled worker instead of wedging. See the node() transport reference.

  • SSR-safe worker resolution. The Node worker resolves without import.meta.resolve, so server-side bundlers (Next.js and similar) load it correctly. See the Next.js SSR guide.

  • Delegation propagation absorbed internally. Delegated decryption transparently retries across the short window while a new delegation propagates to the gateway, so first-attempt delegatedUserDecrypt calls no longer fail spuriously. See Delegated decryption.

Last updated