Skip to main content
Since 0.2.5 the SDK is built on @solana/kit, so a Kit app needs no bridge at all. Cloak’s own types are Kit types:
  • connection is a CloakRpc from createCloakRpc(rpcUrl), not a web3.js Connection.
  • programId, mints and recipients are Kit Address strings, not PublicKey instances.
  • depositorKeypair is a Kit KeyPairSigner, and signer is a Kit transaction signer.
@solana/web3.js is now an optional peer dependency. The only thing that still needs it is the browser wallet-adapter bridge, which hands the wallet a VersionedTransaction to sign.

Which half of this page is yours

Kit apps come in two shapes, and they diverge at the first flow that is submitted for you. A deposit is signed by the funding wallet and posted directly. A private send, a withdrawal or a swap is submitted on your behalf, and each of those requests carries an authenticated sender signed by the end user’s own wallet.
Most Kit stacks are frontends, and a frontend cannot use depositorKeypair. It takes a secret key that a browser wallet never releases. If your Kit app runs in a browser, skip the keypair example below and use the wallet-adapter one. The full contract, including the approval window and how many prompts to expect, is Request authentication.

Install

Browser apps add the wallet adapter and @solana/web3.js, which the adapter bridge needs:

The endpoint value

The submission endpoint is pinned when the SDK is built, and the SDK reads no environment variable for it. Pass the exported constant rather than a host you typed or a value you read from the environment:
CLOAK_RELAY_URL is a convention that the SDK’s own examples and scripts read themselves and pass in as relayUrl. If your Kit app does the same, it is your code doing the reading, and the value still has to be an origin on this build’s allowlist or the call throws. There is no default: omitting relayUrl yields undefined, never production.
Omitting relayUrl, or passing "", makes every flow including deposits throw Viewing key registration is mandatory: relayUrl is required. before any network call. "" is the caller-signed direct-submission signal, but it only takes effect when enforceViewingKeyRegistration is also set to false, because the viewing-key gate fires first. That pair is not a frontend recipe: with a signer present it submits a transfer or withdrawal under the user’s own key, publicly linking it.
A published build reaches exactly one submission endpoint and cannot be repointed by a Kit app, or any other consumer. See Pointing at a non-production endpoint.

Wiring a browser Kit app

Wrap the connected wallet adapter with signerFromWalletAdapter and pass the result as signer. No secret key ever exists in your app.
signerFromWalletAdapter throws if the adapter has no publicKey (not connected). It always provides transaction signing; it adds message signing only when the adapter exposes signMessage. That matters because a wallet without signMessage authenticates requests by signing a deterministic no-op transaction instead — the path a Ledger or Trezor takes. Either way the authenticated sender must be the end user’s own wallet, never an ephemeral or service-held key.

Wiring a server or CLI Kit app

Load the secret key into a KeyPairSigner and pass it as depositorKeypair.
generateKeyPairSigner() gives a throwaway signer for tests, and signerFromKeypair({ secretKey }) accepts an object that already carries raw secret-key bytes.

Migration history: coming from web3.js

This section is historical, for upgrading an integration written against 0.2.4 or earlier. Every example above already uses the current 0.2.5 Kit API; nothing here is a current instruction.

Request authentication

Why sends need a signed sender, the approval window, and both signer shapes.

Wallet integration

Full wallet-adapter wiring, progress callbacks and stale-root retries.

Code examples

Concise snippets to adapt to your Kit app runtime.

Error handling

CloakError categories, parseError, and the stale-root retry template.

Note storage

Where change notes have to be written down, and what each storage export carries.