@oneswap/wallet-cip0103-adapter
v0.1.1
Published
Official CIP-0103 ProviderAdapter for the OneSwap hosted v2 wallet.
Readme
@oneswap/wallet-cip0103-adapter
Official CIP-0103-compatible provider adapter for connecting PartyLayer and other Canton dApps to OneSwap V2 Wallet.
The adapter implements PartyLayer Generic Bridge Path B: the dApp installs this package, creates a ProviderAdapter, and hands it to PartyLayer's provider-registration layer. OneSwap handles authentication, user approval, signing, and ledger submission inside a secure hosted-wallet popup.
Install
npm install @oneswap/wallet-cip0103-adapter @partylayer/coreRequirements:
- Browser environment with popup support
@partylayer/core^0.12.1- ESM-compatible build setup
- The dApp must use the same CAIP-2 network as the selected OneSwap deployment
OneSwap environments
| Environment | Wallet URL | CAIP-2 network |
| --- | --- | --- |
| MainNet | https://oneswap.cc | canton:da-mainnet |
| DevNet | https://devnet.oneswap.cc | canton:da-devnet |
PartyLayer's default network policy is guard. A network mismatch can allow the initial connection but will block transaction-class methods. Always configure the adapter with the exact network used by the dApp.
Quick integration
import { createOneSwapProviderAdapter } from '@oneswap/wallet-cip0103-adapter';
const oneSwapAdapter = createOneSwapProviderAdapter({
walletUrl: 'https://devnet.oneswap.cc',
networkId: 'canton:da-devnet',
});
// Register or return `oneSwapAdapter` from PartyLayer's ProviderAdapter
// registration point in your Generic Bridge integration.For direct integration testing, the underlying CIP-0103 provider is available from the adapter:
const provider = oneSwapAdapter.provider();
await provider.request({
method: 'connect',
params: {
appName: 'PartyLayer Example dApp',
requestId: crypto.randomUUID(),
},
});
const accounts = await provider.request({ method: 'listAccounts' });
const network = await provider.request({ method: 'getActiveNetwork' });The OneSwap popup displays the calling dApp's origin and app name. The user must approve the connection before account information is returned.
Exports
The package exports:
createOneSwapProviderAdapter(options)
OneSwapProviderAdapter
OneSwapCip0103Provider
createOneSwapWalletClient(options)
OneSwapWalletClientIt also exports the related TypeScript option, event, account, session, and result types.
Provider adapter
createOneSwapProviderAdapter(options)
Creates the PartyLayer-facing provider adapter.
const adapter = createOneSwapProviderAdapter({
walletUrl: 'https://oneswap.cc',
networkId: 'canton:da-mainnet',
providerId: 'oneswap-v2',
name: 'OneSwap V2 Wallet',
icon: 'https://oneswap.cc/logo.svg',
connectPath: '/connect',
timeoutMs: 60_000,
});Options
| Option | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| walletUrl | string | Yes | — | OneSwap web origin, without the connect path |
| networkId | string | Yes | — | CAIP-2 Canton network identifier |
| providerId | string | No | oneswap-v2 | Stable provider identifier exposed to PartyLayer |
| name | string | No | OneSwap V2 Wallet | Display name for wallet selection UI |
| icon | string | No | — | Optional provider icon URL |
| connectPath | string | No | /connect | Hosted popup path; must begin with / |
| timeoutMs | number | No | 60000 | Per-request timeout; minimum is 5 seconds |
| popupFeatures | string | No | OneSwap popup defaults | Browser feature string passed to window.open |
OneSwapProviderAdapter
The adapter exposes these fields:
| Field | Value |
| --- | --- |
| providerId | Configured provider ID |
| name | Configured display name |
| type | remote |
| icon | Configured icon, if supplied |
And these methods:
detect(): Promise<boolean>
Returns true in a browser and false during SSR. It does not open the popup or authenticate the user.
provider(): OneSwapCip0103Provider
Returns the stable provider instance used for CIP-0103 requests and events. Repeated calls return the same instance.
restore(): Promise<null>
OneSwap does not silently restore an approved dApp connection after a parent-page reload. This currently returns null; call connect again to establish a fresh user-approved session.
teardown(): void
Removes listeners, rejects outstanding requests, and closes the wallet popup.
CIP-0103 provider methods
Call provider methods through provider.request({ method, params }). params must be an object when present; positional arrays are rejected.
connect
Opens the hosted OneSwap popup and asks the signed-in user to approve the calling dApp origin.
const result = await provider.request({
method: 'connect',
params: {
appName: 'PartyLayer',
requestId: 'connect-001',
},
});
// {
// isConnected: true,
// isNetworkConnected: true
// }appName is optional but strongly recommended because it is shown in the approval UI. requestId may be a string or number.
listAccounts
Returns the connected OneSwap account list.
const accounts = await provider.request({ method: 'listAccounts' });Result shape:
type CIP0103Account = {
primary: true;
partyId: string;
status: 'allocated';
hint: 'OneSwap V2 wallet';
publicKey: string;
namespace: 'oneswap';
networkId: string;
signingProviderId: string;
};getPrimaryAccount
Returns the primary connected account as a single CIP0103Account.
const account = await provider.request({ method: 'getPrimaryAccount' });getActiveNetwork
Returns the configured CAIP-2 network.
const active = await provider.request({ method: 'getActiveNetwork' });
// { networkId: 'canton:da-devnet' }isConnected
Returns the provider's current connection state.
const connected = await provider.request({ method: 'isConnected' });
// booleanstatus
Returns the full provider status snapshot.
const status = await provider.request({ method: 'status' });Result shape:
{
connection: {
isConnected: boolean;
isNetworkConnected: boolean;
};
provider: {
id: string;
version: '0.1.0';
providerType: 'remote';
};
network: {
networkId: string;
};
}signMessage
Requests explicit user approval and signs a non-empty UTF-8 message for the connected wallet party.
const signed = await provider.request({
method: 'signMessage',
params: {
message: 'Sign in to PartyLayer. Nonce: 2cbfe6d0',
},
});Result shape:
{
signature: string;
publicKey: string;
partyId: string;
encoding: 'utf8';
}The message should contain any domain, nonce, expiry, and human-readable intent required by the dApp. OneSwap signs exactly the supplied UTF-8 message after approval.
prepareExecute
Requests explicit user approval, then asks the OneSwap backend to prepare, sign, and submit a non-empty CIP-0103 Daml command array.
const commands = buildReviewedCip0103DamlCommands();
const submitted = await provider.request({
method: 'prepareExecute',
params: { commands },
});Result shape:
{
transactionHash: string;
updateId: string | null;
submittedAt: string;
}Important integration rules:
commandsmust be a non-empty array using the Daml command schema expected by CIP-0103 and@partylayer/core.- OneSwap is the submitter; the dApp must not submit the same transaction again.
- The popup shows a transaction approval before execution.
- A successful result is an execution receipt, not a raw private key or reusable signature.
disconnect
Ends the approved dApp session and clears the provider's connected account state.
await provider.request({ method: 'disconnect' });The provider emits disconnected, statusChanged, and accountsChanged updates.
ledgerApi
Not supported in this release. Calls reject with JSON-RPC code 4200 (Unsupported method). Read balances and activity through the normal PartyLayer or application data path.
Provider events
Subscribe with provider.on(event, listener) and unsubscribe with provider.removeListener(event, listener).
const onAccountsChanged = (accounts: CIP0103Account[]) => {
console.log('OneSwap accounts changed', accounts);
};
provider.on('connected', (account) => {
console.log('Connected OneSwap account', account.partyId);
});
provider.on('accountsChanged', onAccountsChanged);
provider.on('statusChanged', (status) => {
console.log('Provider status', status.connection);
});
provider.on('disconnected', () => {
console.log('OneSwap disconnected');
});
provider.removeListener('accountsChanged', onAccountsChanged);| Event | Payload |
| --- | --- |
| connected | Primary CIP0103Account |
| disconnected | No payload |
| accountsChanged | CIP0103Account[] |
| statusChanged | Provider status snapshot |
For complete cleanup, call provider.close() or adapter.teardown().
Low-level popup client
Most PartyLayer integrations should use OneSwapProviderAdapter. OneSwapWalletClient is exported for integrations that need the raw OneSwap popup protocol.
import { createOneSwapWalletClient } from '@oneswap/wallet-cip0103-adapter';
const client = createOneSwapWalletClient({
walletUrl: 'https://devnet.oneswap.cc',
});
const session = await client.connect({
appName: 'PartyLayer',
network: 'canton:da-devnet',
requestId: 'connect-001',
});Low-level methods
| Method | Result | Popup RPC method |
| --- | --- | --- |
| connect(context) | { accounts, primaryAccount, network } | canton_connect |
| listAccounts() | { accounts } | canton_listAccounts |
| getPrimaryAccount() | WalletAccount | canton_getPrimaryAccount |
| getActiveNetwork() | { network } | canton_getActiveNetwork |
| signMessage(message) | { signature, publicKey, partyId, encoding } | canton_signMessage |
| prepareSignExecute(commands) | Execution receipt | canton_prepareSignExecute |
| submitTransaction(commands) | Execution receipt; alias of prepareSignExecute | canton_prepareSignExecute |
| disconnect() | void | canton_disconnect |
| close() | void; local cleanup and popup close | — |
WalletAccount has this shape:
{
partyId: string;
publicKey: string | null;
network: string;
}Error handling
Provider and client calls reject with an Error carrying a numeric code.
try {
await provider.request({
method: 'signMessage',
params: { message: 'Authenticate this session' },
});
} catch (error) {
const rpcError = error as Error & { code?: number };
if (rpcError.code === 4001) {
// The user rejected the request.
} else {
console.error(rpcError.code, rpcError.message);
}
}| Code | Meaning | Typical cause |
| --- | --- | --- |
| 4001 | User rejected | Connect, signing, or execution approval declined |
| 4100 | Unauthorized | No active approved wallet session |
| 4200 | Unsupported method | Method is unavailable, including ledgerApi |
| 4900 | Disconnected | Popup or approved session disconnected |
| -32602 | Invalid params | Missing, malformed, or empty method parameters |
| -32603 | Internal error | Wallet, signing, or internal processing failure |
| -32000 | Execution error | Backend preparation or ledger submission failed |
Requests also reject if the popup is blocked, closed before responding, or exceeds timeoutMs.
Popup and security model
- OneSwap opens one named popup and reuses it for the approved session.
- The popup sends
oneswap:cip0103:readybefore the first request, preventing startup races. - The adapter validates both
event.sourceand the exact OneSwap wallet origin on every response. - The wallet validates the opener source and calling dApp origin on every request.
- The calling origin is approved dynamically by the user; there is no fixed PartyLayer origin allowlist.
- The OneSwap login token, backend session, and wallet credentials are never returned to the dApp.
- Account access, message signing, and transaction execution follow explicit wallet approval flows.
- Closing the popup, calling
disconnect, or tearing down the adapter invalidates the active connection.
PartyLayer integration checklist
Before enabling OneSwap in a PartyLayer deployment:
- Select the correct OneSwap wallet URL and matching CAIP-2 network.
- Register the
OneSwapProviderAdapterthrough PartyLayer Generic Bridge Path B. - Provide a recognizable
appNamefor the wallet approval screen. - Handle
4001as a normal user-decline outcome. - Subscribe to connection, status, and account events.
- Send only reviewed CIP-0103 Daml command arrays to
prepareExecute. - Treat OneSwap's execution receipt as final submission ownership; do not resubmit it from the dApp.
- Reconnect after a parent-page reload because silent session restoration is not supported.
Package
- npm:
@oneswap/wallet-cip0103-adapter - Current API version:
0.1.0 - PartyLayer peer contract:
@partylayer/core ^0.12.1
