- Sub-accounts:
transfers.build().subaccounts(dappName)returns aSubAccountsBuilder(hung off the builder so a sub-accountinvokeshares the builder'sExecuteOptions/context).invoke(nonce, { calls })queues aComputeAndInvokeagainst the sub-account anonymizer —computeAdditionalData = [dappName, nonce]andinvokeAdditionalDatacompiled from the dappcallsvia the generated anonymizer ABI — and returns the builder so the caller can add the open-note creation and.execute().dappNameaccepts a felt or a short string. Requires the newsubAccountAnonymizerAddressfield on thecreatePrivateTransfersconfig; callingsubaccounts(...)without it throws.identify()anddeployed()on the builder are declared but not yet implemented. @starkware-libs/starknet-privacy-sdk/signerssubpath export:Snip12CallSetSignerandEip712CallSetSigner(starknet.jsSignerInterfaceimplementations for authorizing privacy-pool invocations with legacy SN wallets andEth712Account/ EVM wallets), plus thecomputeCallSetHash/computeCallSet712Hashgolden-vector oracles. Both signers accept an optionaladditionalDatabound into the signedCallSetmessage (empty by default, matching the pool). SDK core stays signer-agnostic.
- Removed pool-mode selection: the screening attestation
Optionsuffix is now always appended toapply_actionscalldata, so the SDK only supports screening-capable pools (whoseapply_actionstakes the trailingOption<ScreeningAttestation>parameter). Class-hash detection, thePoolCapabilityModeexport, and thepoolModeoverride oncreatePrivateTransfers()are gone; pre-screening pools now revert on calldata arity. - Testing:
createCompatibilityAliceTransfers()is renamed tocreateUnattestedAliceTransfers()— with pool-mode selection removed it can no longer omit the attestation suffix; it now sendsOption::None, which the screening pool still rejects for deposits (SCREENING_REQUIRED).
- Opening a channel to a new recipient no longer issues a second
discoverChannels("total-only")request. The recipient-discovery walk already runs to the sentinel, so it now returns the outgoing-channel count, and the compiler reuses that count as the new channel's index — halving the outgoing discovery work on that path. Providers whose targeted discovery stops short of the sentinel (e.g. on-chainContractDiscovery) still fall back to the dedicated count query.
discoverChannels("total-only")now paginates outgoing channel discovery to the sentinel instead of issuing a single request. A sender with at leastmax_channels(default 256) outgoing channels caps the first page before the sentinel, so the service returned nototal_n_channels; the count surfaced asundefinedand the compiler turned it into channel index0, producing aNON_ZERO_VALUEwrite-once collision when opening a channel to the next (e.g. 257th) recipient. The count is now derived once discovery completes, and a missing total after completion throws instead of being silently coerced.
- Prove retries:
proveTransactionnow retries transient failures (prover service-busy-32005and HTTP 503) with exponential backoff. Configurable via a newretry?: { maxRetries?; baseDelayMs? }option onProvingServiceConfig,ProvingServiceProofProviderOptions, and thecreatePrivateTransfersprovingProviderconfig (defaults: 3 retries, 1s base → 1s/2s/4s; each backoff is capped atMAX_PROVE_BACKOFF_MS= 30s so a largemaxRetriescan't schedule an unbounded wait). Pass{ maxRetries: 0 }to disable, or raise the values to retry more before raising to the caller. Non-transient errors (invalid tx, screening rejection, network failure) still surface on the first attempt, andgetSpecVersion/isHealthynever retry so health checks stay fast. The busy-32005code is retried on both the plain-fetch and OHTTP transports; an HTTP 503 is retried on plain fetch only. Exported theProvingRetryOptionstype and a newProvingServiceHttpError(carriesstatus) thrown for non-2xx HTTP responses on the plain-fetch transport. simulate()method onPrivateTransfersInterface,PrivateTransfersBuilder, andTokenOperationsBuilderfor gas fee estimation without real proof generation.SimulateOptionstype with a requiredprovider(node provider the mock prover calls to build proof facts — the minimal{ address, signer }account carries none) and an optionalvalidateSignatureflag.- Testing: exported
ScreeningCallMockProofProviderfrom the/testingentry point. It extendsCallMockProofProviderto sign each deposit's screening attestation with the canonical test screener key, so integration suites can drive a screening-capable pool's deposit path end to end. computeAndInvokebuilder method onPrivateTransfersBuilder: queues aComputeAndInvokeclient action that, after the private operations, queries the target contract'sprivacy_compute(with the derived identity key andcomputeAdditionalData) and forwards its result plusinvokeAdditionalDatatoprivacy_invoke_with_computation. The call builder receives the same{ openNotes, withdrawals, poolAddress }asinvoke. Mutually exclusive withinvoke(one invoke-phase action per transaction). Supported by theMockPoolContractsimulate flow.
proveTransactionno longer fails immediately on a transient prover error: by default it retries service-busy / HTTP 503 up to 3 times with exponential backoff (see Added). This adds up to ~7s of latency before a busy prover error surfaces; setretry: { maxRetries: 0 }to restore the previous fail-fast behavior.
- Privacy pool role-management ABI changed (
PrivacyPoolABIregenerated). Thestarkware_utilsupgrade replaced the monolithicRolesComponentwithCommonRolesComponent, so the per-role typed selectors (is_app_governor/register_app_governor/remove_security_governor/…) are removed and replaced by the genericgrant_role(role, account),revoke_role(role, account),has_role(role, account), andrenounce(role)taking aRoleenum. Tooling that called the old role selectors must migrate.
- Screening v2:
ProveTransactionResult.additional_data(typed, optional) parsed from the prove response, carrying an optionalsignature(ScreeningSignature). Backward-compatible: responses without it parse unchanged; unknown fields are still rejected by the strict schema. ExportedAdditionalData/ScreeningSignaturetypes. - Screening v2:
ScreeningRejected(terminal — sanctioned address) andScreeningUnavailable(transient — screener unreachable) error classes, plusscreeningErrorFromProvingError()mapping the interceptor's opaqueaddress_blocked/screening_unavailablereasons (JSON-RPC code 10000). Other code-10000 errors returnundefinedso the caller rethrows the original rather than mislabeling a transient fault as terminal. - Screening v2:
apply_actionscalldata carries the screening attestation as a trailing Serde-encodedOption—[0x1]when absent,[0x0, issued_at, sig_r, sig_s]when the prove response carries a signature (Cairo'sOptionSerde tags:Some= 0,None= 1).Proofgains an optionaladditionalDatarelaying the prove response'sadditional_data. Emitted only against a screening-capable pool, identified with zero RPC calls: the prove response's payload is headed by the pool's class hash, which the SDK looks up against the pinned class hashes of the deployed pre-screening pools on SN_MAIN and SN_SEPOLIA. A pinned hash gets today's calldata (no suffix); any other class hash is treated as screening-capable, so the SDK activates automatically when an upgraded pool deploys, and one SDK build is compatible with both pool versions. - Screening v2: exported
PoolCapabilityMode, andcreatePrivateTransfers()gains an optionalpoolModeoverride for deployments whose pool class hash isn't pinned (e.g. local devnet/test pools built from source). - Screening v2 (testing):
ScreeningCallMockProofProvidersigns each deposit's screening attestation with the canonical fixture screener key, andcreateCompatibilityAliceTransfers()builds a compatibility-mode transfers object. The devnet suite deploys the screening-capable pool, exercises an attested deposit (screening mode), and asserts the pool rejects an un-attested deposit (compatibility mode).
createPrivateTransfers()accountparameter type relaxed fromAccountto{ address, signer }. A full starknet.jsAccountis structurally assignable, so existing callers compile unchanged. Smart wallets that need account-formatted signatures (e.g. owner + guardian merge) can now pass{ address: account.address, signer: customProofSigner }to override the signer used for proof invocations. Closes #718.
PrivateTransfersUserinterface ({ address, signer }) exported frominterfaces.tsfor callers who want to type their own minimal account shape.
- Renamed
MockSwapHelpertoMockSwapAnonymizerin@starkware-libs/starknet-privacy-sdk/testing(and itsbrowserre-export). Update imports accordingly.
- Fixed
INDEX_NOT_SEQUENTIALerror when the paymaster fee token equals the swap output token (toToken) in a private swap. The compiler was emittingCreateEncNoteat index N+1 beforeCreateOpenNoteat index N for the same token. Note-creation actions are now accumulated in a single list in processing order instead of separate enc/open arrays. OhttpClientnow builds the inner OHTTP request URL with a synthetic origin (https://ohttp-target.invalid) instead of${gatewayUrl}${path}. Previously, whengatewayUrlincluded a reverse-proxy path prefix (e.g.https://api.example.com/discovery), that prefix leaked into the encrypted inner request path and produced a 404 inside the OHTTP envelope (OHTTP inner response /v1/sync/outgoing_state failed (404)). The OHTTP gateway routes by path only, so the synthetic origin is inert; only the per-callpathargument is used for routing.
- Switch
starknetdependency from custom fork (starkware-libs/starknet.js#PRIVACY-0.14.2-RC.2) to officialstarknet@10.0.0-beta.6 ProofInvocationtype now importsINVOKE_TXN_V3from@starknet-io/starknet-types-0101(was@starknet-io/starknet-types-010)- Removed
@starknet-io/starknet-types-09direct dependency (now resolved transitively via starknet) - Node.js >= 24 now required (due to
ohttp-tsdependency using WebCrypto APIs) fetchHistoryoption renamed fromblockReftoblockIdentifier(type:BlockIdentifier)HistoryPage.blockRefchanged fromstringtoBlockIdentifierHistoryCursor.beginBlockNumberis now optional (undefinedon first page; server resolves fromblock_ref)
- OHTTP (Oblivious HTTP, RFC 9458) support for
IndexerDiscoveryProvider— encrypts all discovery requests and responses at the application layer using HPKE, independent of TLS (#TBD)- Enable with
new IndexerDiscoveryProvider(url, contract, { ohttp: true }) - Optional key pinning via
{ ohttp: { publicKeyConfig: bytes } }to skip/ohttp-keysfetch - Optional OHTTP relay support via
{ ohttp: { relayUrl: "..." } }for client IP hiding; relay URL is used as-is (target API path is encrypted inside the OHTTP envelope) - Warns at construction time when
gatewayUrlis plain HTTP and no key config is pinned (TOFU key discovery is vulnerable to MITM over unencrypted transport)
- Enable with
- Export
OhttpClientclass for advanced OHTTP usage outsideIndexerDiscoveryProvider - OHTTP envelope encryption support for
ProvingServiceProofProvider— encrypts proving requests and decrypts compressed responses (decrypt-then-decompress)- Enable with
new ProvingServiceProofProvider(url, chainId, { ohttp: true }) - Same relay/key-pinning options as
IndexerDiscoveryProvider - Also available via
ProofProviderConfig.ohttpincreatePrivateTransfers()factory
- Enable with
- Export
OhttpOptiontype for reuse in consumer code feeaction type inclassifyTransactionfor withdrawals to fee recipients (e.g. paymaster forwarder), distinct from regular withdrawalsClassifyOptions.feeRecipientsparameter onclassifyTransactionto identify fee recipient addressesNote.createdis now populated byIndexerDiscoveryProviderfrom the discovery service's per-noteblock_number(slot'slast_update_block), enabling clients to enforce the 10-block maturity rule before spending
block_refin API models now accepts block hash (hex string), block number (integer), or tag ("latest","pre_confirmed","l1_accepted"). Wire format is backwards compatible — block hashes remain plain hex strings.discoverNotesanddiscoverChannelsaccept optionalblockIdentifierparam to pin discovery reads to a specific block- Compiler passes
ExecuteOptions.provingBlockIdto discovery asblockIdentifier, ensuring discovery and proving use the same block state - Switch devnet testing from
ProvingServiceProofProvidertoCallMockProofProviderwith--proof-mode none(proofFacts validated, proof ignored) - Run channel and note discovery concurrently during transaction compilation to reduce latency
ProofInvocationFactorybuildsINVOKE_TXN_V3manually instead of usingRpcChannel.prototype.buildTransaction()(removed in v10)ProvingService.proveTransaction()parameter type changed fromINVOKE_TXN_V3toProofInvocation(same underlying type)- Remove devnet
getStarknetVersionmonkey-patch anddeclareWithoutVersionCheckworkaround (starknet.js#1561 resolved in v10) - Fee withdrawals no longer prevent
transferSelf(reorganization) detection - Fee withdrawals are excluded from incoming transfer actions (receiver doesn't see sender's fee)
- Added
ohttp-ts(RFC 9458 implementation by Cloudflare)
- History endpoint support via
IndexerDiscoveryProvider.fetchHistory()for paginated transaction history (#641) - Classify history events into user-facing actions: deposits, withdrawals, transfers (#637)
invalidateProofNonceCache()onPrivateTransfersInterfaceto clear the cached pool nonce and force a fresh fetch on the next call (#663)nodeUrloption onProofProviderConfigto enable pool nonce fetching and caching inProvingServiceProofProvider(#663)- Execution continuation on previously created invocation (#643)
- Remove
depositorfrom Note storage layout (#661) - Upgrade Scarb to 2.17.0-rc.4 (Sierra 1.8.0)
- Rename npm package from
starknet-sdkto@starkware-libs/starknet-privacy-sdk, published to GitHub Packages PrivateTransfersBuilder.invoke()now accepts only acallBuilder(args) => CallDetailscallback (raw/manual invoke input removed).SimplePrivateTransfersInterface.swap()now takes executor address directly instead of an object (swap(fromToken, fromAmount, toToken, executorAddress)).
- Switch
starknetdependency fromm-kus/starknet.jsfork tostarkware-industries/starknet.js invokecall builder now receives structured context:{ openNotes, withdrawals, poolAddress }.
- Align
computeMessageHashwith Cairo after class hash was added to message payload (#573, #571) - Fix outgoing channel sync skipping first channel in indexer discovery (#555)
- Invoke action support (#499)
Initial dev release.