PartyLayer
Try Demo

Wallets & Adapters

PartyLayer includes built-in wallet adapters and supports custom adapters for any Canton wallet. Wallets are discovered through the registry and CIP-0103 native provider detection.

The default catalog is included with the kit; no per-wallet installation is required. Custom adapters are an advanced extension point. For transports and a page per integration, see the Canton wallet directory.

Built-in Wallets

WalletNetworksOpt-inAdditional setup
Console Walletdevnet, testnet, mainnetNoIncluded
5N Loopdevnet, mainnetNoIncluded
Cantor8devnet, mainnetNoIncluded
Brondevnet, testnet, mainnetYesYour OAuth/API configuration
Nightlydevnet, testnet, mainnetNoIncluded
Cauri Walletdevnet, mainnetNoIncluded
OneSwap V2 Walletdevnet, mainnetNoIncluded
SendmainnetNoIncluded
Walleymainnet, testnet, devnetNoIncluded
WalletConnectdevnet, testnet, mainnetYesYour project ID
ℹ️ Note
Wallets marked Opt-in (Bron, WalletConnect) require explicit configuration: pass bron for OAuth/API access and walletConnectwith your Cloud project id. Their runtime dependencies are included. The default catalog supplies the other supported wallets for the configured network and channel.

Capability Matrix

Not every wallet supports every operation. This matrix is generated from the active SDK integrations. Check it before building features that depend on specific capabilities.

WalletconnectsignMessagesignTransactionsubmitTransactionledgerApirestore
Console Walletsupportedsupportednonesupportednonesupported
5N Loopsupportedsupportednonesupportedsupportedsupported
Cantor8supportednonenonesupportednonenone
Bronsupportedsupportedsupportednonesupportedsupported
Nightlysupportedsupportednonesupportedsupportedsupported
Cauri Walletsupportedsupportednonesupportednonenone
OneSwap V2 Walletsupportedsupportednonesupportednonenone
Sendsupportedsupportednonesupportedsupportedsupported
Walleysupportedsupportednonesupportednonenone
WalletConnectsupportedsupportednonesupportedsupportedsupported

Capability Notes

  • Loop / Nightly / Send, signTransaction: these wallets combine signing and submission into a single step. Use submitTransaction directly instead of the separate sign-then-submit pattern. Calling signTransaction on any of them throws CapabilityNotSupportedError pointing you at this fix.
  • Send: the default catalog uses the native announce path. It is Mainnet-only in the catalog and requires the wallet's own login/passkey approval. The standalone compatibility adapter has its own provider identity guard; it is not required for the default kit. See the Send guide.
  • Loop, ledgerApi (limited): Supports POST /v2/state/acs, GET /v2/state/acs/active-contracts, POST /v2/commands/submit, and POST /v2/commands/submit-and-wait. Other endpoints are not available, for broader Ledger API access, check the active capabilities of Nightly or Bron.
  • Cantor8: hosted popup integration. Use submitTransactionfor its combined sign-and-execute flow. Separate message signing, transaction signing and Ledger API access are not exposed by this integration.
  • Bron, submitTransaction: Bron is a remote signer (OAuth), it signs commands but does not submit them directly to the ledger. Pair signTransaction with your own participant submission, or call ledgerApi against /v2/commands/submit-and-wait and let Bron sign the pre-built command. Requires the bron configuration with auth and api.
  • Session restore: support depends on the wallet and its live authentication. A stored PartyLayer session alone does not establish a wallet connection. Official popup providers are probed before restoration; OneSwap requires a fresh explicit connection. See Advanced → Session Persistence for per-wallet behavior.

Adding Bron (Enterprise)

tsx
import { PartyLayerKit, ConnectButton } from '@partylayer/react';

const walletConnect = { projectId: 'your-walletconnect-project-id' };
const bron = {
  auth: {
    clientId: 'your-client-id',
    redirectUri: 'https://your-app.com/auth/callback',
    authorizationUrl: 'https://auth.bron.example/authorize',
    tokenUrl: 'https://auth.bron.example/token',
  },
  api: { baseUrl: 'https://api.bron.example' },
};

<PartyLayerKit network="mainnet" appName="My dApp" walletConnect={walletConnect} bron={bron}>
  <ConnectButton />
</PartyLayerKit>

Wallet Discovery

PartyLayer discovers wallets through two mechanisms:

1. Registry Discovery

On initialization, the SDK fetches the wallet registry from registry.partylayer.xyz. The registry contains wallet metadata, names, icons, capabilities, install hints, and supported networks. Entries are validated against the registry schema on every build; they are not signed today.

If the registry is unreachable, the SDK gracefully falls back to adapter-only discovery, which can preserve known wallet entries. Hosted-wallet login and ledger access still require their services.

2. CIP-0103 Native Detection

The SDK scans window.canton.* for CIP-0103 compliant providers injected by wallet extensions. Native wallets appear first in the wallet list with a "Native" badge.

typescript
// What the SDK does internally:
import { discoverInjectedProviders } from '@partylayer/provider';

const providers = discoverInjectedProviders();
// → [{ id: 'console', provider: CIP0103Provider }, ...]

getBuiltinAdapters

Returns the synchronous legacy subset (Loop, Cantor8, Nightly), not the complete default catalog:

typescript
import { getBuiltinAdapters } from '@partylayer/sdk';

const adapters = getBuiltinAdapters();
// → [LoopAdapter, Cantor8Adapter, NightlyAdapter]

Creating a Custom Adapter

New wallets should follow CIP-0103 Path A or B. The following advanced example documents the existing WalletAdapter contract for application-owned integrations and test fixtures:

typescript
import type {
  WalletAdapter, AdapterContext, AdapterDetectResult,
  AdapterConnectResult, Session, SignMessageParams,
  SignTransactionParams, SubmitTransactionParams,
} from '@partylayer/core';

class MyWalletAdapter implements WalletAdapter {
  readonly walletId = 'my-wallet' as WalletId;
  readonly name = 'My Custom Wallet';

  getCapabilities() {
    return ['connect', 'disconnect', 'signMessage', 'signTransaction'];
  }

  async detectInstalled(): Promise<AdapterDetectResult> {
    const installed = typeof window !== 'undefined' && !!window.myWallet;
    return { installed, reason: installed ? undefined : 'Extension not found' };
  }

  async connect(ctx: AdapterContext, opts?: { timeoutMs?: number }): Promise<AdapterConnectResult> {
    const result = await window.myWallet.connect({
      appName: ctx.appName,
      network: ctx.network,
    });
    return {
      partyId: result.partyId,
      session: { metadata: result.metadata },
      capabilities: this.getCapabilities(),
    };
  }

  async disconnect(ctx: AdapterContext, session: Session): Promise<void> {
    await window.myWallet.disconnect();
  }

  async signMessage(ctx: AdapterContext, session: Session, params: SignMessageParams) {
    const sig = await window.myWallet.sign(params.message);
    return {
      signature: sig,
      partyId: session.partyId,
      message: params.message,
    };
  }

  async signTransaction(ctx: AdapterContext, session: Session, params: SignTransactionParams) {
    const result = await window.myWallet.signTx(params.tx);
    return {
      signedTx: result.signedPayload,
      transactionHash: result.txHash,
      partyId: session.partyId,
    };
  }
}

Registering at Runtime

Register adapters at runtime using the client's registerAdapter method:

typescript
import { createPartyLayer } from '@partylayer/sdk';

const client = createPartyLayer({ network: 'mainnet', app: { name: 'My dApp' } });

// Register your custom adapter
client.registerAdapter(new MyWalletAdapter());

// Now it appears in listWallets()
const wallets = await client.listWallets();

WalletAdapter Interface

PropTypeDefaultDescription
walletIdreadonly WalletId—Unique wallet identifier.
namereadonly string—Human-readable wallet name.
getCapabilities()() => CapabilityKey[]—Return supported capabilities.
detectInstalled()() => Promise<AdapterDetectResult>—Check if wallet is installed. Returns { installed, reason? }.
connect()(ctx, opts?) => Promise<AdapterConnectResult>—Establish wallet connection. Returns { partyId, session, capabilities }.
disconnect()(ctx, session) => Promise<void>—Close connection. Required.
restore?()(ctx, persisted) => Promise<Session | null>optionalRestore a persisted session.
signMessage?()(ctx, session, params) => Promise<SignedMessage>optionalSign arbitrary message.
signTransaction?()(ctx, session, params) => Promise<SignedTransaction>optionalSign transaction.
submitTransaction?()(ctx, session, params) => Promise<TxReceipt>optionalSign and submit transaction.
ledgerApi?()(ctx, session, params) => Promise<LedgerApiResult>optionalProxy a JSON Ledger API request.
PreviousVanilla JSNextSend