decane-connect-kit 2.7.5 → 2.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +17 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +583 -537
- package/dist/index.d.ts +583 -537
- package/dist/index.js +17 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,476 +1,176 @@
|
|
|
1
1
|
import * as _simplewebauthn_browser from '@simplewebauthn/browser';
|
|
2
2
|
import React, { ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
symbol: string;
|
|
13
|
-
decimals: number;
|
|
4
|
+
interface RecoveryShareFile {
|
|
5
|
+
version: number;
|
|
6
|
+
type: 'decane-recovery-share';
|
|
7
|
+
shareSetVersion: number;
|
|
8
|
+
kdf: 'pbkdf2-sha256';
|
|
9
|
+
kdfParams: {
|
|
10
|
+
iterations: number;
|
|
11
|
+
salt: string;
|
|
14
12
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
icon: string;
|
|
25
|
-
rdns?: string;
|
|
26
|
-
chainSupport: ChainSupport;
|
|
27
|
-
evmProvider?: EIP1193Provider;
|
|
28
|
-
solanaProvider?: StandardWallet;
|
|
29
|
-
tronProvider?: TronProvider;
|
|
30
|
-
bitcoinProvider?: BitcoinProvider;
|
|
31
|
-
}
|
|
32
|
-
type CAIP25Method = "wallet_requestPermissions" | "wallet_revokePermissions" | "wallet_getPermissions" | "wallet_sendTransaction" | "wallet_signMessage" | "wallet_signTypedData";
|
|
33
|
-
interface ChainScope {
|
|
34
|
-
methods: CAIP25Method[];
|
|
35
|
-
accounts: string[];
|
|
36
|
-
events?: string[];
|
|
37
|
-
}
|
|
38
|
-
interface CAIP25SessionRequest {
|
|
39
|
-
requiredScopes: Partial<Record<string, ChainScope>>;
|
|
40
|
-
optionalScopes: Partial<Record<string, ChainScope>>;
|
|
13
|
+
cipher: 'aes-256-gcm';
|
|
14
|
+
iv: string;
|
|
15
|
+
ciphertext: string;
|
|
16
|
+
addresses: {
|
|
17
|
+
evm: string;
|
|
18
|
+
solana: string;
|
|
19
|
+
};
|
|
20
|
+
passwordHint: string | null;
|
|
21
|
+
createdAt: string;
|
|
41
22
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
23
|
+
|
|
24
|
+
interface PortableBackup {
|
|
25
|
+
version: number;
|
|
26
|
+
type: 'decane-portable-backup';
|
|
27
|
+
shareSetVersion: number;
|
|
28
|
+
kdf: 'pbkdf2-sha256';
|
|
29
|
+
kdfParams: {
|
|
30
|
+
iterations: number;
|
|
31
|
+
salt: string;
|
|
32
|
+
};
|
|
33
|
+
cipher: 'aes-256-gcm';
|
|
34
|
+
iv: string;
|
|
35
|
+
ciphertext: string;
|
|
36
|
+
addresses: {
|
|
37
|
+
evm: string;
|
|
38
|
+
solana: string;
|
|
39
|
+
};
|
|
40
|
+
passwordHint: string | null;
|
|
41
|
+
createdAt: string;
|
|
45
42
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
|
|
44
|
+
interface BalanceResult {
|
|
45
|
+
/** Smallest unit — wei for EVM, lamports for Solana. */
|
|
46
|
+
raw: bigint;
|
|
47
|
+
/** Human-readable amount in whole native units, e.g. "1.2345". */
|
|
48
|
+
formatted: string;
|
|
49
|
+
/** Native currency symbol, e.g. "ETH", "MATIC", "SOL". */
|
|
50
|
+
symbol: string;
|
|
51
|
+
/** Decimals of the native currency (18 for EVM, 9 for Solana). */
|
|
52
|
+
decimals: number;
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
+
|
|
55
|
+
interface Eip1193Provider {
|
|
54
56
|
request(args: {
|
|
55
57
|
method: string;
|
|
56
|
-
params?: unknown[];
|
|
58
|
+
params?: unknown[] | object;
|
|
57
59
|
}): Promise<unknown>;
|
|
58
|
-
on(event: string, handler: (...args: unknown[]) => void):
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
readonly
|
|
62
|
-
readonly solanaWallets: UnifiedWalletAccount[];
|
|
63
|
-
readonly multiChainWallets: UnifiedWalletAccount[];
|
|
64
|
-
readonly tronWallets: UnifiedWalletAccount[];
|
|
65
|
-
readonly bitcoinWallets: UnifiedWalletAccount[];
|
|
66
|
-
connect(wallet: UnifiedWalletAccount, preferredChain?: ChainType): Promise<void>;
|
|
67
|
-
disconnect(): Promise<void>;
|
|
68
|
-
addChain(chain: ChainDescriptor): void;
|
|
69
|
-
removeChain(chainId: string): void;
|
|
70
|
-
getChain(chainId: string): ChainDescriptor | undefined;
|
|
71
|
-
readonly chains: ChainDescriptor[];
|
|
72
|
-
readonly connectedWallet: UnifiedWalletAccount | null;
|
|
73
|
-
readonly activeSession: ActiveSession | null;
|
|
74
|
-
readonly activeChain: string | null;
|
|
60
|
+
on(event: string, handler: (...args: unknown[]) => void): this;
|
|
61
|
+
removeListener(event: string, handler: (...args: unknown[]) => void): this;
|
|
62
|
+
/** Marks this as the Decane provider (parallel to wallets' isMetaMask etc.). */
|
|
63
|
+
readonly isDecane: true;
|
|
75
64
|
}
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
interface EthereumProviderOptions {
|
|
66
|
+
/** Initial chain id (numeric). Defaults to the first configured EVM chain, else 1. */
|
|
67
|
+
chainId?: number;
|
|
68
|
+
/** Per-chain RPC overrides ('evm:8453' -> url). Falls back to Decane's defaults. */
|
|
69
|
+
rpcUrls?: Record<string, string>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Build an EIP-1193 provider over a connected Decane social client.
|
|
73
|
+
*
|
|
74
|
+
* `signAuthorization` (EIP-7702) is wired only when the client exposes it — that
|
|
75
|
+
* requires the TEE signer to support the authorization signing path.
|
|
76
|
+
*/
|
|
77
|
+
declare function createEthereumProvider(client: DecaneConnect, opts?: EthereumProviderOptions): Eip1193Provider;
|
|
78
|
+
|
|
79
|
+
interface SignedAuthorization {
|
|
80
|
+
chainId: number;
|
|
81
|
+
address: string;
|
|
82
|
+
nonce: number;
|
|
83
|
+
yParity: number;
|
|
84
|
+
r: string;
|
|
85
|
+
s: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type Chain = `evm:${number}` | `solana:${'mainnet' | 'devnet'}` | `tron:${'mainnet' | 'shasta' | 'nile'}`;
|
|
89
|
+
interface DecaneConnectConfig {
|
|
90
|
+
/** Dashboard project ID (public). Sent with every request so the backend can
|
|
91
|
+
* confirm the API key below actually belongs to this project. */
|
|
92
|
+
appId: string;
|
|
78
93
|
apiKey: string;
|
|
79
|
-
|
|
94
|
+
chains: Chain[];
|
|
95
|
+
authMethods: Array<'google' | 'email' | 'kingschat'>;
|
|
80
96
|
/**
|
|
81
|
-
* Scopes requested from KingsChat. Defaults to
|
|
82
|
-
* is what KingsChat's own SDK asks for and is
|
|
97
|
+
* Scopes requested from KingsChat at sign-in. Defaults to
|
|
98
|
+
* `['send_chat_message']`, which is what KingsChat's own SDK asks for and is
|
|
99
|
+
* enough to establish identity. Widen only if the app actually calls
|
|
100
|
+
* KingsChat APIs on the user's behalf — the consent screen lists every scope,
|
|
101
|
+
* so asking for more than you use costs conversions.
|
|
83
102
|
*/
|
|
84
103
|
kingsChatScopes?: string[];
|
|
85
|
-
promptPin?: () => Promise<string>;
|
|
86
104
|
apiBaseUrl?: string;
|
|
87
|
-
|
|
88
|
-
|
|
105
|
+
sessionDurationMinutes?: number;
|
|
106
|
+
promptPin?: () => Promise<string>;
|
|
89
107
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
108
|
+
* Require a fresh WebAuthn assertion for every signature, instead of letting
|
|
109
|
+
* an unlocked session sign freely until it expires. The TEE session stays
|
|
110
|
+
* warm — this costs one authenticator prompt per signature, not a re-auth or
|
|
111
|
+
* re-attestation — and the check is enforced inside the enclave, not here.
|
|
92
112
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* without it the page can look frozen. It is rendered by `<DecaneKit>` itself,
|
|
96
|
-
* as a portal, and injects its own theme tokens.
|
|
113
|
+
* Default false, which preserves the session-signing model: unlock once, sign
|
|
114
|
+
* for the session's lifetime with no further prompts.
|
|
97
115
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
116
|
+
* Two things worth knowing before turning this on:
|
|
117
|
+
* - Multi-step flows prompt per leg. An ERC-20 approve + swap is two
|
|
118
|
+
* prompts, not one.
|
|
119
|
+
* - The policy is declared by the client at session open, so it hardens a
|
|
120
|
+
* leaked session handle (useless without the authenticator) but a fully
|
|
121
|
+
* compromised page could open a session without it. Making it
|
|
122
|
+
* unbypassable requires the policy to come from the server per user or
|
|
123
|
+
* per project; that is not implemented yet.
|
|
104
124
|
*/
|
|
105
|
-
|
|
125
|
+
requireAssertionPerSignature?: boolean;
|
|
126
|
+
rpId?: string;
|
|
127
|
+
rpName?: string;
|
|
128
|
+
rpcUrls?: Record<string, string>;
|
|
129
|
+
teeUrl?: string;
|
|
106
130
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
131
|
+
* Persist the live session (handle + JWT) in sessionStorage so a page RELOAD
|
|
132
|
+
* silently resumes it — no repeat passkey/sign-in. Survives reloads, cleared
|
|
133
|
+
* on tab close. Default true. Set false to require a fresh unlock on every
|
|
134
|
+
* page load (stricter, but the reload friction that motivated this returns).
|
|
135
|
+
*/
|
|
136
|
+
persistSession?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Offer to save a recovery-share file at signup. **Default false** since
|
|
139
|
+
* 2.7.4 — opt in explicitly with `true`.
|
|
109
140
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
141
|
+
* The offer existed because a new device could not otherwise get a device
|
|
142
|
+
* share. Server-assisted provisioning now covers that case: every wallet is
|
|
143
|
+
* enrolled at creation, un-enrolled wallets repair themselves on the next
|
|
144
|
+
* unlock, and a returning user is provisioned from their sign-in alone. For
|
|
145
|
+
* almost every app the dialog is now a password prompt during onboarding that
|
|
146
|
+
* buys nothing, so it is off unless asked for.
|
|
147
|
+
*
|
|
148
|
+
* Recovery files themselves are unchanged and still work — `rotateShares()`
|
|
149
|
+
* issues one on demand, and `promptForRecoveryFile` still accepts one during
|
|
150
|
+
* recovery. Turn this back on if you want users to hold an offline fallback
|
|
151
|
+
* that does not depend on Decane being reachable.
|
|
115
152
|
*/
|
|
116
|
-
|
|
153
|
+
offerRecoveryAtSignup?: boolean;
|
|
154
|
+
/** Ask the user whether they want a recovery share and, if so, a password for it. */
|
|
155
|
+
onRecoveryShareOffer?: (addresses: {
|
|
156
|
+
evmAddress: string;
|
|
157
|
+
solanaAddress: string;
|
|
158
|
+
}) => Promise<{
|
|
159
|
+
wants: boolean;
|
|
160
|
+
password: string;
|
|
161
|
+
passwordHint?: string;
|
|
162
|
+
}>;
|
|
163
|
+
/** Hand the built file + suggested filename to the dApp, which owns the actual download. */
|
|
164
|
+
onRecoveryFileReady?: (file: RecoveryShareFile, filename: string) => Promise<void>;
|
|
165
|
+
/** Prompt for a recovery-share file (and its password) during Flow B. Return null to cancel. */
|
|
166
|
+
promptForRecoveryFile?: () => Promise<{
|
|
167
|
+
value: unknown;
|
|
168
|
+
getPassword: () => Promise<string | null>;
|
|
169
|
+
} | null>;
|
|
117
170
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* getToken() runs when the user clicks the button; wire it to however you
|
|
122
|
-
* already obtain a token from your auth system (e.g. after your own login
|
|
123
|
-
* flow completes). Configure the issuer and JWKS URL for this token
|
|
124
|
-
* against your project in the dashboard first. `providerId` is only
|
|
125
|
-
* needed when the project has more than one custom provider configured.
|
|
126
|
-
*/
|
|
127
|
-
customAuth?: {
|
|
128
|
-
label: string;
|
|
129
|
-
providerId?: string;
|
|
130
|
-
getToken: () => Promise<string>;
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
interface DecaneConfig {
|
|
134
|
-
appId: string;
|
|
135
|
-
chains?: ChainDescriptor[];
|
|
136
|
-
supportedChainIds?: string[];
|
|
137
|
-
networks?: "evm" | "solana" | "tron" | "bitcoin" | "all";
|
|
138
|
-
defaultChain?: string;
|
|
139
|
-
theme?: "light" | "dark" | "auto";
|
|
140
|
-
mode?: ConnectMode;
|
|
141
|
-
social?: SocialConfig;
|
|
142
|
-
}
|
|
143
|
-
interface EIP1193Provider {
|
|
144
|
-
request(args: {
|
|
145
|
-
method: string;
|
|
146
|
-
params?: unknown[];
|
|
147
|
-
}): Promise<unknown>;
|
|
148
|
-
on(event: string, handler: (...args: unknown[]) => void): void;
|
|
149
|
-
removeListener(event: string, handler: (...args: unknown[]) => void): void;
|
|
150
|
-
}
|
|
151
|
-
interface StandardWallet {
|
|
152
|
-
name: string;
|
|
153
|
-
icon: string;
|
|
154
|
-
features: Record<string, unknown>;
|
|
155
|
-
accounts: StandardWalletAccount[];
|
|
156
|
-
}
|
|
157
|
-
interface StandardWalletAccount {
|
|
158
|
-
address: string;
|
|
159
|
-
publicKey: Uint8Array;
|
|
160
|
-
chains: string[];
|
|
161
|
-
}
|
|
162
|
-
interface TronProvider {
|
|
163
|
-
request(args: {
|
|
164
|
-
method: string;
|
|
165
|
-
params?: unknown[] | Record<string, unknown>;
|
|
166
|
-
}): Promise<unknown>;
|
|
167
|
-
on(event: string, handler: (...args: unknown[]) => void): void;
|
|
168
|
-
removeListener(event: string, handler: (...args: unknown[]) => void): void;
|
|
169
|
-
}
|
|
170
|
-
interface BitcoinProvider {
|
|
171
|
-
requestAccounts(): Promise<string[] | Array<{
|
|
172
|
-
address: string;
|
|
173
|
-
}>>;
|
|
174
|
-
getAccounts?(): Promise<string[] | Array<{
|
|
175
|
-
address: string;
|
|
176
|
-
}>>;
|
|
177
|
-
signMessage(message: string, ...args: unknown[]): Promise<string>;
|
|
178
|
-
sendBitcoin?(toAddress: string, satoshis: number, options?: unknown): Promise<string>;
|
|
179
|
-
send?(params: unknown): Promise<string>;
|
|
180
|
-
signPsbt?(psbtHex: string, options?: unknown): Promise<string>;
|
|
181
|
-
on?(event: string, handler: (...args: unknown[]) => void): void;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
declare function createDecane(config: DecaneConfig): DecaneProvider;
|
|
185
|
-
|
|
186
|
-
declare class ApiClient {
|
|
187
|
-
private readonly baseUrl;
|
|
188
|
-
private readonly apiKey;
|
|
189
|
-
private readonly appId;
|
|
190
|
-
constructor(baseUrl: string, apiKey: string, appId: string);
|
|
191
|
-
private _request;
|
|
192
|
-
getGoogleInitUrl(): Promise<{
|
|
193
|
-
url: string;
|
|
194
|
-
}>;
|
|
195
|
-
/**
|
|
196
|
-
* Exchange a Google ID token the app already holds for a Decane session.
|
|
197
|
-
* Resolves to the SAME identity as the redirect flow, so one Google account
|
|
198
|
-
* means one wallet across web and mobile.
|
|
199
|
-
*/
|
|
200
|
-
authGoogleToken(idToken: string): Promise<AuthResult>;
|
|
201
|
-
/** The project's KingsChat clientId, so the dApp never has to hardcode it. */
|
|
202
|
-
getKingsChatConfig(): Promise<{
|
|
203
|
-
clientId: string;
|
|
204
|
-
authorizationUrl: string;
|
|
205
|
-
}>;
|
|
206
|
-
/**
|
|
207
|
-
* Exchange a KingsChat access token for a Decane session. The backend spends
|
|
208
|
-
* the token against KingsChat's own API to establish the identity — it is
|
|
209
|
-
* never trusted on its face, and never stored.
|
|
210
|
-
*/
|
|
211
|
-
authKingsChat(accessToken: string): Promise<AuthResult>;
|
|
212
|
-
authEmailStart(email: string): Promise<void>;
|
|
213
|
-
authEmailVerify(email: string, code: string): Promise<AuthResult>;
|
|
214
|
-
getAddresses(jwt: string): Promise<{
|
|
215
|
-
evm: string | null;
|
|
216
|
-
solana: string | null;
|
|
217
|
-
tron: string | null;
|
|
218
|
-
}>;
|
|
219
|
-
putShare(jwt: string, share: {
|
|
220
|
-
ciphertext: Uint8Array;
|
|
221
|
-
iv: Uint8Array;
|
|
222
|
-
wrappedShareMeta: WrappedShareMeta;
|
|
223
|
-
evmAddress: string;
|
|
224
|
-
solanaAddress: string;
|
|
225
|
-
tronAddress: string;
|
|
226
|
-
}): Promise<void>;
|
|
227
|
-
recordTransaction(jwt: string, tx: {
|
|
228
|
-
chain: string;
|
|
229
|
-
txHash?: string;
|
|
230
|
-
to?: string;
|
|
231
|
-
value?: string;
|
|
232
|
-
kind?: string;
|
|
233
|
-
status?: string;
|
|
234
|
-
metadata?: Record<string, unknown>;
|
|
235
|
-
}): Promise<TransactionRecord>;
|
|
236
|
-
getTransactions(jwt: string, limit?: number): Promise<TransactionRecord[]>;
|
|
237
|
-
getWebAuthnRegisterOptions(jwt: string, rpId: string, rpName: string): Promise<_simplewebauthn_browser.PublicKeyCredentialCreationOptionsJSON>;
|
|
238
|
-
postWebAuthnRegister(jwt: string, response: _simplewebauthn_browser.RegistrationResponseJSON, origin: string): Promise<void>;
|
|
239
|
-
/**
|
|
240
|
-
* Exchange a token from the developer's own auth system for a Decane
|
|
241
|
-
* session. `providerId` is only needed when the project has more than one
|
|
242
|
-
* provider configured.
|
|
243
|
-
*/
|
|
244
|
-
authExternal(token: string, providerId?: string): Promise<AuthResult>;
|
|
245
|
-
/**
|
|
246
|
-
* Returns null when this user has no server-registered passkey, which is the
|
|
247
|
-
* expected answer for wallets created before passkey sign-in existed or for
|
|
248
|
-
* PIN-only users — the caller falls back to the normal sign-in flow.
|
|
249
|
-
*/
|
|
250
|
-
getWebAuthnLoginOptions(userId: string, rpId: string): Promise<_simplewebauthn_browser.PublicKeyCredentialRequestOptionsJSON | null>;
|
|
251
|
-
postWebAuthnLogin(userId: string, response: _simplewebauthn_browser.AuthenticationResponseJSON, origin: string): Promise<AuthResult>;
|
|
252
|
-
revoke(jwt: string): Promise<void>;
|
|
253
|
-
hasRecoveryBackup(jwt: string): Promise<boolean>;
|
|
254
|
-
getRecoveryBackup(jwt: string): Promise<{
|
|
255
|
-
wrappedDeviceShare: Uint8Array;
|
|
256
|
-
iv: Uint8Array;
|
|
257
|
-
unlockMethod: 'passkey';
|
|
258
|
-
credentialId: Uint8Array;
|
|
259
|
-
prfSalt: Uint8Array;
|
|
260
|
-
formatVersion: number;
|
|
261
|
-
} | null>;
|
|
262
|
-
putRecoveryBackup(jwt: string, backup: {
|
|
263
|
-
wrappedDeviceShare: Uint8Array;
|
|
264
|
-
iv: Uint8Array;
|
|
265
|
-
unlockMethod: 'passkey';
|
|
266
|
-
credentialId: Uint8Array;
|
|
267
|
-
prfSalt: Uint8Array;
|
|
268
|
-
}): Promise<void>;
|
|
269
|
-
deleteRecoveryBackup(jwt: string): Promise<void>;
|
|
270
|
-
markRecoveryShareSaved(jwt: string): Promise<void>;
|
|
271
|
-
getRecoveryStatus(jwt: string): Promise<{
|
|
272
|
-
hasRecoveryShare: boolean;
|
|
273
|
-
savedAt: string | null;
|
|
274
|
-
nagged: boolean;
|
|
275
|
-
shareSetVersion: number;
|
|
276
|
-
/**
|
|
277
|
-
* Whether this wallet is enrolled for server-assisted provisioning, i.e.
|
|
278
|
-
* whether a new device can be given a device share from login alone.
|
|
279
|
-
* Optional because backends older than this field simply omit it — treat
|
|
280
|
-
* `undefined` as "unknown", never as "not enrolled".
|
|
281
|
-
*/
|
|
282
|
-
enrolled?: boolean;
|
|
283
|
-
}>;
|
|
284
|
-
dismissRecoveryNag(jwt: string): Promise<void>;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
type RecoveryProgress = {
|
|
288
|
-
type: 'passkey-attempt';
|
|
289
|
-
} | {
|
|
290
|
-
type: 'passkey-failed';
|
|
291
|
-
reason: string;
|
|
292
|
-
} | {
|
|
293
|
-
type: 'recovery-file-prompt';
|
|
294
|
-
} | {
|
|
295
|
-
type: 'password-prompt';
|
|
296
|
-
passwordHint: string | null;
|
|
297
|
-
} | {
|
|
298
|
-
type: 'recovery-verifying';
|
|
299
|
-
} | {
|
|
300
|
-
type: 'rotated';
|
|
301
|
-
shareSetVersion: number;
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
interface RecoveryShareFile {
|
|
305
|
-
version: number;
|
|
306
|
-
type: 'decane-recovery-share';
|
|
307
|
-
shareSetVersion: number;
|
|
308
|
-
kdf: 'pbkdf2-sha256';
|
|
309
|
-
kdfParams: {
|
|
310
|
-
iterations: number;
|
|
311
|
-
salt: string;
|
|
312
|
-
};
|
|
313
|
-
cipher: 'aes-256-gcm';
|
|
314
|
-
iv: string;
|
|
315
|
-
ciphertext: string;
|
|
316
|
-
addresses: {
|
|
317
|
-
evm: string;
|
|
318
|
-
solana: string;
|
|
319
|
-
};
|
|
320
|
-
passwordHint: string | null;
|
|
321
|
-
createdAt: string;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
interface PortableBackup {
|
|
325
|
-
version: number;
|
|
326
|
-
type: 'decane-portable-backup';
|
|
327
|
-
shareSetVersion: number;
|
|
328
|
-
kdf: 'pbkdf2-sha256';
|
|
329
|
-
kdfParams: {
|
|
330
|
-
iterations: number;
|
|
331
|
-
salt: string;
|
|
332
|
-
};
|
|
333
|
-
cipher: 'aes-256-gcm';
|
|
334
|
-
iv: string;
|
|
335
|
-
ciphertext: string;
|
|
336
|
-
addresses: {
|
|
337
|
-
evm: string;
|
|
338
|
-
solana: string;
|
|
339
|
-
};
|
|
340
|
-
passwordHint: string | null;
|
|
341
|
-
createdAt: string;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
interface BalanceResult {
|
|
345
|
-
/** Smallest unit — wei for EVM, lamports for Solana. */
|
|
346
|
-
raw: bigint;
|
|
347
|
-
/** Human-readable amount in whole native units, e.g. "1.2345". */
|
|
348
|
-
formatted: string;
|
|
349
|
-
/** Native currency symbol, e.g. "ETH", "MATIC", "SOL". */
|
|
350
|
-
symbol: string;
|
|
351
|
-
/** Decimals of the native currency (18 for EVM, 9 for Solana). */
|
|
352
|
-
decimals: number;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
interface Eip1193Provider {
|
|
356
|
-
request(args: {
|
|
357
|
-
method: string;
|
|
358
|
-
params?: unknown[] | object;
|
|
359
|
-
}): Promise<unknown>;
|
|
360
|
-
on(event: string, handler: (...args: unknown[]) => void): this;
|
|
361
|
-
removeListener(event: string, handler: (...args: unknown[]) => void): this;
|
|
362
|
-
/** Marks this as the Decane provider (parallel to wallets' isMetaMask etc.). */
|
|
363
|
-
readonly isDecane: true;
|
|
364
|
-
}
|
|
365
|
-
interface EthereumProviderOptions {
|
|
366
|
-
/** Initial chain id (numeric). Defaults to the first configured EVM chain, else 1. */
|
|
367
|
-
chainId?: number;
|
|
368
|
-
/** Per-chain RPC overrides ('evm:8453' -> url). Falls back to Decane's defaults. */
|
|
369
|
-
rpcUrls?: Record<string, string>;
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Build an EIP-1193 provider over a connected Decane social client.
|
|
373
|
-
*
|
|
374
|
-
* `signAuthorization` (EIP-7702) is wired only when the client exposes it — that
|
|
375
|
-
* requires the TEE signer to support the authorization signing path.
|
|
376
|
-
*/
|
|
377
|
-
declare function createEthereumProvider(client: DecaneConnect, opts?: EthereumProviderOptions): Eip1193Provider;
|
|
378
|
-
|
|
379
|
-
interface SignedAuthorization {
|
|
380
|
-
chainId: number;
|
|
381
|
-
address: string;
|
|
382
|
-
nonce: number;
|
|
383
|
-
yParity: number;
|
|
384
|
-
r: string;
|
|
385
|
-
s: string;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
type Chain = `evm:${number}` | `solana:${'mainnet' | 'devnet'}` | `tron:${'mainnet' | 'shasta' | 'nile'}`;
|
|
389
|
-
interface DecaneConnectConfig {
|
|
390
|
-
/** Dashboard project ID (public). Sent with every request so the backend can
|
|
391
|
-
* confirm the API key below actually belongs to this project. */
|
|
392
|
-
appId: string;
|
|
393
|
-
apiKey: string;
|
|
394
|
-
chains: Chain[];
|
|
395
|
-
authMethods: Array<'google' | 'email' | 'kingschat'>;
|
|
396
|
-
/**
|
|
397
|
-
* Scopes requested from KingsChat at sign-in. Defaults to
|
|
398
|
-
* `['send_chat_message']`, which is what KingsChat's own SDK asks for and is
|
|
399
|
-
* enough to establish identity. Widen only if the app actually calls
|
|
400
|
-
* KingsChat APIs on the user's behalf — the consent screen lists every scope,
|
|
401
|
-
* so asking for more than you use costs conversions.
|
|
402
|
-
*/
|
|
403
|
-
kingsChatScopes?: string[];
|
|
404
|
-
apiBaseUrl?: string;
|
|
405
|
-
sessionDurationMinutes?: number;
|
|
406
|
-
promptPin?: () => Promise<string>;
|
|
407
|
-
/**
|
|
408
|
-
* Require a fresh WebAuthn assertion for every signature, instead of letting
|
|
409
|
-
* an unlocked session sign freely until it expires. The TEE session stays
|
|
410
|
-
* warm — this costs one authenticator prompt per signature, not a re-auth or
|
|
411
|
-
* re-attestation — and the check is enforced inside the enclave, not here.
|
|
412
|
-
*
|
|
413
|
-
* Default false, which preserves the session-signing model: unlock once, sign
|
|
414
|
-
* for the session's lifetime with no further prompts.
|
|
415
|
-
*
|
|
416
|
-
* Two things worth knowing before turning this on:
|
|
417
|
-
* - Multi-step flows prompt per leg. An ERC-20 approve + swap is two
|
|
418
|
-
* prompts, not one.
|
|
419
|
-
* - The policy is declared by the client at session open, so it hardens a
|
|
420
|
-
* leaked session handle (useless without the authenticator) but a fully
|
|
421
|
-
* compromised page could open a session without it. Making it
|
|
422
|
-
* unbypassable requires the policy to come from the server per user or
|
|
423
|
-
* per project; that is not implemented yet.
|
|
424
|
-
*/
|
|
425
|
-
requireAssertionPerSignature?: boolean;
|
|
426
|
-
rpId?: string;
|
|
427
|
-
rpName?: string;
|
|
428
|
-
rpcUrls?: Record<string, string>;
|
|
429
|
-
teeUrl?: string;
|
|
430
|
-
/**
|
|
431
|
-
* Persist the live session (handle + JWT) in sessionStorage so a page RELOAD
|
|
432
|
-
* silently resumes it — no repeat passkey/sign-in. Survives reloads, cleared
|
|
433
|
-
* on tab close. Default true. Set false to require a fresh unlock on every
|
|
434
|
-
* page load (stricter, but the reload friction that motivated this returns).
|
|
435
|
-
*/
|
|
436
|
-
persistSession?: boolean;
|
|
437
|
-
/**
|
|
438
|
-
* Offer to save a recovery-share file at signup. **Default false** since
|
|
439
|
-
* 2.7.4 — opt in explicitly with `true`.
|
|
440
|
-
*
|
|
441
|
-
* The offer existed because a new device could not otherwise get a device
|
|
442
|
-
* share. Server-assisted provisioning now covers that case: every wallet is
|
|
443
|
-
* enrolled at creation, un-enrolled wallets repair themselves on the next
|
|
444
|
-
* unlock, and a returning user is provisioned from their sign-in alone. For
|
|
445
|
-
* almost every app the dialog is now a password prompt during onboarding that
|
|
446
|
-
* buys nothing, so it is off unless asked for.
|
|
447
|
-
*
|
|
448
|
-
* Recovery files themselves are unchanged and still work — `rotateShares()`
|
|
449
|
-
* issues one on demand, and `promptForRecoveryFile` still accepts one during
|
|
450
|
-
* recovery. Turn this back on if you want users to hold an offline fallback
|
|
451
|
-
* that does not depend on Decane being reachable.
|
|
452
|
-
*/
|
|
453
|
-
offerRecoveryAtSignup?: boolean;
|
|
454
|
-
/** Ask the user whether they want a recovery share and, if so, a password for it. */
|
|
455
|
-
onRecoveryShareOffer?: (addresses: {
|
|
456
|
-
evmAddress: string;
|
|
457
|
-
solanaAddress: string;
|
|
458
|
-
}) => Promise<{
|
|
459
|
-
wants: boolean;
|
|
460
|
-
password: string;
|
|
461
|
-
passwordHint?: string;
|
|
462
|
-
}>;
|
|
463
|
-
/** Hand the built file + suggested filename to the dApp, which owns the actual download. */
|
|
464
|
-
onRecoveryFileReady?: (file: RecoveryShareFile, filename: string) => Promise<void>;
|
|
465
|
-
/** Prompt for a recovery-share file (and its password) during Flow B. Return null to cancel. */
|
|
466
|
-
promptForRecoveryFile?: () => Promise<{
|
|
467
|
-
value: unknown;
|
|
468
|
-
getPassword: () => Promise<string | null>;
|
|
469
|
-
} | null>;
|
|
470
|
-
/**
|
|
471
|
-
* Every successful recovery/rotation invalidates the previous recovery
|
|
472
|
-
* file — this MUST prompt for a new password and block progress until the
|
|
473
|
-
* dApp confirms the user saved the new file (see MIGRATE_SSS_RECOVERY.md §10).
|
|
171
|
+
* Every successful recovery/rotation invalidates the previous recovery
|
|
172
|
+
* file — this MUST prompt for a new password and block progress until the
|
|
173
|
+
* dApp confirms the user saved the new file (see MIGRATE_SSS_RECOVERY.md §10).
|
|
474
174
|
*/
|
|
475
175
|
onRecoveryRotated?: (addresses: {
|
|
476
176
|
evmAddress: string;
|
|
@@ -669,112 +369,458 @@ interface DecaneConnect {
|
|
|
669
369
|
nonce: number;
|
|
670
370
|
}): Promise<SignedAuthorization>;
|
|
671
371
|
/**
|
|
672
|
-
* The current session's access token (the Decane JWT). Use it to authenticate
|
|
673
|
-
* the user to your own backend (e.g. a sponsored-bundler proxy); verify it
|
|
674
|
-
* server-side against backend.decane.app/.well-known/jwks.json. Null with no
|
|
675
|
-
* live session.
|
|
372
|
+
* The current session's access token (the Decane JWT). Use it to authenticate
|
|
373
|
+
* the user to your own backend (e.g. a sponsored-bundler proxy); verify it
|
|
374
|
+
* server-side against backend.decane.app/.well-known/jwks.json. Null with no
|
|
375
|
+
* live session.
|
|
376
|
+
*/
|
|
377
|
+
getAccessToken(): string | null;
|
|
378
|
+
signSolanaTransaction(tx: Uint8Array): Promise<Uint8Array>;
|
|
379
|
+
/**
|
|
380
|
+
* Sign a Tron transaction. Pass the transaction's `raw_data_hex` (the value
|
|
381
|
+
* TronWeb puts on a built transaction). The enclave computes the txID
|
|
382
|
+
* (sha256(raw_data)) and signs it with the same secp256k1 key as the EVM
|
|
383
|
+
* wallet; returns the 65-byte recoverable signature as 0x-hex. Attach it to
|
|
384
|
+
* the transaction's `signature` array and broadcast via TronWeb / a full node.
|
|
385
|
+
*/
|
|
386
|
+
signTronTransaction(rawDataHex: string): Promise<string>;
|
|
387
|
+
/**
|
|
388
|
+
* Record a transaction this wallet broadcast, so it appears in the user's
|
|
389
|
+
* history (and the developer dashboard). EVM `sendTransaction` records itself
|
|
390
|
+
* automatically; call this for Solana/Tron transactions your dApp broadcasts,
|
|
391
|
+
* or to attach a `confirmed`/`failed` status update to an existing hash.
|
|
392
|
+
*/
|
|
393
|
+
recordTransaction(tx: RecordTransactionInput): Promise<TransactionRecord>;
|
|
394
|
+
/** The user's transaction history, most recent first. Requires a live session. */
|
|
395
|
+
getTransactionHistory(limit?: number): Promise<TransactionRecord[]>;
|
|
396
|
+
disconnect(): Promise<void>;
|
|
397
|
+
getAddresses(): {
|
|
398
|
+
evm?: string;
|
|
399
|
+
solana?: string;
|
|
400
|
+
tron?: string;
|
|
401
|
+
} | null;
|
|
402
|
+
/**
|
|
403
|
+
* Native-token balance for a chain (defaults to the first configured EVM
|
|
404
|
+
* chain, else Solana). Read-only public data — works even while the wallet
|
|
405
|
+
* is locked. Returns raw (wei/lamports), a human `formatted` string, the
|
|
406
|
+
* native `symbol`, and `decimals`.
|
|
407
|
+
*/
|
|
408
|
+
getBalance(chain?: string): Promise<BalanceResult>;
|
|
409
|
+
/** Native balances across every configured chain the wallet has an address for. */
|
|
410
|
+
getBalances(): Promise<Array<{
|
|
411
|
+
chain: string;
|
|
412
|
+
balance: BalanceResult | null;
|
|
413
|
+
}>>;
|
|
414
|
+
/**
|
|
415
|
+
* Voluntary share rotation — after a suspected device compromise, or just
|
|
416
|
+
* to invalidate an old recovery file. Requires a fresh WebAuthn assertion.
|
|
417
|
+
* Returns the new recovery-share file (the caller still owns delivering it
|
|
418
|
+
* to the user — this does not download anything itself).
|
|
419
|
+
*/
|
|
420
|
+
rotateShares(opts: {
|
|
421
|
+
password: string;
|
|
422
|
+
passwordHint?: string;
|
|
423
|
+
}): Promise<RecoveryShareFile>;
|
|
424
|
+
/**
|
|
425
|
+
* The two-share bearer portable backup (device + recovery). This file plus
|
|
426
|
+
* its password gives complete control of the wallet — see the mandatory
|
|
427
|
+
* warning-screen requirements in MIGRATE_SSS_RECOVERY.md §10. Requires a
|
|
428
|
+
* fresh WebAuthn assertion and rotates the share set on every export.
|
|
429
|
+
*/
|
|
430
|
+
exportPortableBackup(opts: {
|
|
431
|
+
password: string;
|
|
432
|
+
passwordHint?: string;
|
|
433
|
+
}): Promise<PortableBackup>;
|
|
434
|
+
/** Whether the user has ever saved a recovery-share file (UX flag only — Decane never stores the share). */
|
|
435
|
+
hasRecoveryShare(): Promise<boolean>;
|
|
436
|
+
/** True at most once per account: no recovery share saved, never nagged, wallet holds value. */
|
|
437
|
+
shouldPromptRecovery(): Promise<boolean>;
|
|
438
|
+
/** Call regardless of the user's answer — the recovery nag fires once, ever. */
|
|
439
|
+
dismissRecoveryPrompt(): Promise<void>;
|
|
440
|
+
/** Whether a wrapped-share backup exists on the server. */
|
|
441
|
+
hasBackup(): Promise<boolean>;
|
|
442
|
+
/** Delete the server-side backup. Disables Flow A recovery. */
|
|
443
|
+
deleteBackup(): Promise<void>;
|
|
444
|
+
on(event: SdkEvent, handler: (...args: unknown[]) => void): void;
|
|
445
|
+
off(event: SdkEvent, handler: (...args: unknown[]) => void): void;
|
|
446
|
+
}
|
|
447
|
+
interface WrappedShareMeta {
|
|
448
|
+
unlockMethod: 'passkey' | 'pin';
|
|
449
|
+
credentialId?: string;
|
|
450
|
+
prfSalt?: string;
|
|
451
|
+
pinSalt?: string;
|
|
452
|
+
pinIterations?: number;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Who the user is, as the identity provider just described them.
|
|
456
|
+
*
|
|
457
|
+
* Passed through from the provider at sign-in and never stored by Decane — the
|
|
458
|
+
* backend keeps only an HMAC and a masked identifier, so there is no profile to
|
|
459
|
+
* look up later. Cache what you need at sign-in if you want to show a name
|
|
460
|
+
* after a page reload.
|
|
461
|
+
*
|
|
462
|
+
* Every field is optional because providers differ in what they release, and a
|
|
463
|
+
* user can withhold most of it. Email sign-in returns an empty profile.
|
|
464
|
+
*/
|
|
465
|
+
interface AuthProfile {
|
|
466
|
+
name?: string;
|
|
467
|
+
email?: string;
|
|
468
|
+
picture?: string;
|
|
469
|
+
}
|
|
470
|
+
interface AuthResult {
|
|
471
|
+
jwt: string;
|
|
472
|
+
isNewUser: boolean;
|
|
473
|
+
hasShare: boolean;
|
|
474
|
+
userId: string;
|
|
475
|
+
profile?: AuthProfile;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
declare class ApiClient {
|
|
479
|
+
private readonly baseUrl;
|
|
480
|
+
private readonly apiKey;
|
|
481
|
+
private readonly appId;
|
|
482
|
+
constructor(baseUrl: string, apiKey: string, appId: string);
|
|
483
|
+
private _request;
|
|
484
|
+
getGoogleInitUrl(): Promise<{
|
|
485
|
+
url: string;
|
|
486
|
+
}>;
|
|
487
|
+
/**
|
|
488
|
+
* Exchange a Google ID token the app already holds for a Decane session.
|
|
489
|
+
* Resolves to the SAME identity as the redirect flow, so one Google account
|
|
490
|
+
* means one wallet across web and mobile.
|
|
491
|
+
*/
|
|
492
|
+
authGoogleToken(idToken: string): Promise<AuthResult>;
|
|
493
|
+
/** The project's KingsChat clientId, so the dApp never has to hardcode it. */
|
|
494
|
+
getKingsChatConfig(): Promise<{
|
|
495
|
+
clientId: string;
|
|
496
|
+
authorizationUrl: string;
|
|
497
|
+
}>;
|
|
498
|
+
/**
|
|
499
|
+
* Exchange a KingsChat access token for a Decane session. The backend spends
|
|
500
|
+
* the token against KingsChat's own API to establish the identity — it is
|
|
501
|
+
* never trusted on its face, and never stored.
|
|
502
|
+
*/
|
|
503
|
+
authKingsChat(accessToken: string): Promise<AuthResult>;
|
|
504
|
+
authEmailStart(email: string): Promise<void>;
|
|
505
|
+
authEmailVerify(email: string, code: string): Promise<AuthResult>;
|
|
506
|
+
getAddresses(jwt: string): Promise<{
|
|
507
|
+
evm: string | null;
|
|
508
|
+
solana: string | null;
|
|
509
|
+
tron: string | null;
|
|
510
|
+
}>;
|
|
511
|
+
putShare(jwt: string, share: {
|
|
512
|
+
ciphertext: Uint8Array;
|
|
513
|
+
iv: Uint8Array;
|
|
514
|
+
wrappedShareMeta: WrappedShareMeta;
|
|
515
|
+
evmAddress: string;
|
|
516
|
+
solanaAddress: string;
|
|
517
|
+
tronAddress: string;
|
|
518
|
+
}): Promise<void>;
|
|
519
|
+
recordTransaction(jwt: string, tx: {
|
|
520
|
+
chain: string;
|
|
521
|
+
txHash?: string;
|
|
522
|
+
to?: string;
|
|
523
|
+
value?: string;
|
|
524
|
+
kind?: string;
|
|
525
|
+
status?: string;
|
|
526
|
+
metadata?: Record<string, unknown>;
|
|
527
|
+
}): Promise<TransactionRecord>;
|
|
528
|
+
getTransactions(jwt: string, limit?: number): Promise<TransactionRecord[]>;
|
|
529
|
+
getWebAuthnRegisterOptions(jwt: string, rpId: string, rpName: string): Promise<_simplewebauthn_browser.PublicKeyCredentialCreationOptionsJSON>;
|
|
530
|
+
postWebAuthnRegister(jwt: string, response: _simplewebauthn_browser.RegistrationResponseJSON, origin: string): Promise<void>;
|
|
531
|
+
/**
|
|
532
|
+
* Exchange a token from the developer's own auth system for a Decane
|
|
533
|
+
* session. `providerId` is only needed when the project has more than one
|
|
534
|
+
* provider configured.
|
|
535
|
+
*/
|
|
536
|
+
authExternal(token: string, providerId?: string): Promise<AuthResult>;
|
|
537
|
+
/**
|
|
538
|
+
* Returns null when this user has no server-registered passkey, which is the
|
|
539
|
+
* expected answer for wallets created before passkey sign-in existed or for
|
|
540
|
+
* PIN-only users — the caller falls back to the normal sign-in flow.
|
|
541
|
+
*/
|
|
542
|
+
getWebAuthnLoginOptions(userId: string, rpId: string): Promise<_simplewebauthn_browser.PublicKeyCredentialRequestOptionsJSON | null>;
|
|
543
|
+
postWebAuthnLogin(userId: string, response: _simplewebauthn_browser.AuthenticationResponseJSON, origin: string): Promise<AuthResult>;
|
|
544
|
+
revoke(jwt: string): Promise<void>;
|
|
545
|
+
hasRecoveryBackup(jwt: string): Promise<boolean>;
|
|
546
|
+
getRecoveryBackup(jwt: string): Promise<{
|
|
547
|
+
wrappedDeviceShare: Uint8Array;
|
|
548
|
+
iv: Uint8Array;
|
|
549
|
+
unlockMethod: 'passkey';
|
|
550
|
+
credentialId: Uint8Array;
|
|
551
|
+
prfSalt: Uint8Array;
|
|
552
|
+
formatVersion: number;
|
|
553
|
+
} | null>;
|
|
554
|
+
putRecoveryBackup(jwt: string, backup: {
|
|
555
|
+
wrappedDeviceShare: Uint8Array;
|
|
556
|
+
iv: Uint8Array;
|
|
557
|
+
unlockMethod: 'passkey';
|
|
558
|
+
credentialId: Uint8Array;
|
|
559
|
+
prfSalt: Uint8Array;
|
|
560
|
+
}): Promise<void>;
|
|
561
|
+
deleteRecoveryBackup(jwt: string): Promise<void>;
|
|
562
|
+
markRecoveryShareSaved(jwt: string): Promise<void>;
|
|
563
|
+
getRecoveryStatus(jwt: string): Promise<{
|
|
564
|
+
hasRecoveryShare: boolean;
|
|
565
|
+
savedAt: string | null;
|
|
566
|
+
nagged: boolean;
|
|
567
|
+
shareSetVersion: number;
|
|
568
|
+
/**
|
|
569
|
+
* Whether this wallet is enrolled for server-assisted provisioning, i.e.
|
|
570
|
+
* whether a new device can be given a device share from login alone.
|
|
571
|
+
* Optional because backends older than this field simply omit it — treat
|
|
572
|
+
* `undefined` as "unknown", never as "not enrolled".
|
|
573
|
+
*/
|
|
574
|
+
enrolled?: boolean;
|
|
575
|
+
}>;
|
|
576
|
+
dismissRecoveryNag(jwt: string): Promise<void>;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
type RecoveryProgress = {
|
|
580
|
+
type: 'passkey-attempt';
|
|
581
|
+
} | {
|
|
582
|
+
type: 'passkey-failed';
|
|
583
|
+
reason: string;
|
|
584
|
+
} | {
|
|
585
|
+
type: 'recovery-file-prompt';
|
|
586
|
+
} | {
|
|
587
|
+
type: 'password-prompt';
|
|
588
|
+
passwordHint: string | null;
|
|
589
|
+
} | {
|
|
590
|
+
type: 'recovery-verifying';
|
|
591
|
+
} | {
|
|
592
|
+
type: 'rotated';
|
|
593
|
+
shareSetVersion: number;
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
type ChainType = "evm" | "solana" | "tron" | "bitcoin";
|
|
597
|
+
type ChainSupport = ChainType[];
|
|
598
|
+
interface ChainDescriptor {
|
|
599
|
+
id: string;
|
|
600
|
+
type: ChainType;
|
|
601
|
+
name: string;
|
|
602
|
+
nativeCurrency: {
|
|
603
|
+
name: string;
|
|
604
|
+
symbol: string;
|
|
605
|
+
decimals: number;
|
|
606
|
+
};
|
|
607
|
+
rpcUrl?: string;
|
|
608
|
+
blockExplorerUrl?: string;
|
|
609
|
+
iconUrl?: string;
|
|
610
|
+
chainId?: number;
|
|
611
|
+
isCustom?: boolean;
|
|
612
|
+
}
|
|
613
|
+
interface UnifiedWalletAccount {
|
|
614
|
+
id: string;
|
|
615
|
+
name: string;
|
|
616
|
+
icon: string;
|
|
617
|
+
rdns?: string;
|
|
618
|
+
chainSupport: ChainSupport;
|
|
619
|
+
evmProvider?: EIP1193Provider;
|
|
620
|
+
solanaProvider?: StandardWallet;
|
|
621
|
+
tronProvider?: TronProvider;
|
|
622
|
+
bitcoinProvider?: BitcoinProvider;
|
|
623
|
+
}
|
|
624
|
+
type CAIP25Method = "wallet_requestPermissions" | "wallet_revokePermissions" | "wallet_getPermissions" | "wallet_sendTransaction" | "wallet_signMessage" | "wallet_signTypedData";
|
|
625
|
+
interface ChainScope {
|
|
626
|
+
methods: CAIP25Method[];
|
|
627
|
+
accounts: string[];
|
|
628
|
+
events?: string[];
|
|
629
|
+
}
|
|
630
|
+
interface CAIP25SessionRequest {
|
|
631
|
+
requiredScopes: Partial<Record<string, ChainScope>>;
|
|
632
|
+
optionalScopes: Partial<Record<string, ChainScope>>;
|
|
633
|
+
}
|
|
634
|
+
interface CAIP25SessionResult {
|
|
635
|
+
sessionId: string;
|
|
636
|
+
grantedScopes: Partial<Record<string, ChainScope>>;
|
|
637
|
+
}
|
|
638
|
+
interface ActiveSession {
|
|
639
|
+
sessionId: string;
|
|
640
|
+
grantedScopes: Partial<Record<string, ChainScope>>;
|
|
641
|
+
walletId: string;
|
|
642
|
+
walletType: ChainType | "multi";
|
|
643
|
+
createdAt: number;
|
|
644
|
+
}
|
|
645
|
+
interface DecaneProvider {
|
|
646
|
+
request(args: {
|
|
647
|
+
method: string;
|
|
648
|
+
params?: unknown[];
|
|
649
|
+
}): Promise<unknown>;
|
|
650
|
+
on(event: string, handler: (...args: unknown[]) => void): void;
|
|
651
|
+
off(event: string, handler: (...args: unknown[]) => void): void;
|
|
652
|
+
readonly wallets: UnifiedWalletAccount[];
|
|
653
|
+
readonly evmWallets: UnifiedWalletAccount[];
|
|
654
|
+
readonly solanaWallets: UnifiedWalletAccount[];
|
|
655
|
+
readonly multiChainWallets: UnifiedWalletAccount[];
|
|
656
|
+
readonly tronWallets: UnifiedWalletAccount[];
|
|
657
|
+
readonly bitcoinWallets: UnifiedWalletAccount[];
|
|
658
|
+
connect(wallet: UnifiedWalletAccount, preferredChain?: ChainType): Promise<void>;
|
|
659
|
+
disconnect(): Promise<void>;
|
|
660
|
+
addChain(chain: ChainDescriptor): void;
|
|
661
|
+
removeChain(chainId: string): void;
|
|
662
|
+
getChain(chainId: string): ChainDescriptor | undefined;
|
|
663
|
+
readonly chains: ChainDescriptor[];
|
|
664
|
+
readonly connectedWallet: UnifiedWalletAccount | null;
|
|
665
|
+
readonly activeSession: ActiveSession | null;
|
|
666
|
+
readonly activeChain: string | null;
|
|
667
|
+
}
|
|
668
|
+
type ConnectMode = "all" | "social" | "wallets" | "evm" | "solana" | "tron" | "evm+social" | "solana+social" | "tron+social" | "evm+tron" | "evm+tron+social";
|
|
669
|
+
interface SocialConfig {
|
|
670
|
+
apiKey: string;
|
|
671
|
+
authMethods?: ("google" | "email" | "kingschat")[];
|
|
672
|
+
/**
|
|
673
|
+
* Scopes requested from KingsChat. Defaults to `['send_chat_message']`, which
|
|
674
|
+
* is what KingsChat's own SDK asks for and is enough to establish identity.
|
|
676
675
|
*/
|
|
677
|
-
|
|
678
|
-
|
|
676
|
+
kingsChatScopes?: string[];
|
|
677
|
+
promptPin?: () => Promise<string>;
|
|
678
|
+
apiBaseUrl?: string;
|
|
679
|
+
chains?: string[];
|
|
680
|
+
rpcUrls?: Record<string, string>;
|
|
679
681
|
/**
|
|
680
|
-
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
*
|
|
682
|
+
* Show the built-in full-screen status overlay while a wallet is being
|
|
683
|
+
* created or unlocked. Default **true**.
|
|
684
|
+
*
|
|
685
|
+
* The overlay exists because those flows can take several seconds and often
|
|
686
|
+
* run right after a Google redirect, when no modal of yours is mounted — so
|
|
687
|
+
* without it the page can look frozen. It is rendered by `<DecaneKit>` itself,
|
|
688
|
+
* as a portal, and injects its own theme tokens.
|
|
689
|
+
*
|
|
690
|
+
* Set false to suppress it and render your own. Everything it displays is
|
|
691
|
+
* already available to you: `useSocialAuth()` exposes `phase`
|
|
692
|
+
* (`"creating" | "unlocking" | null`) plus the `isCreatingWallet` /
|
|
693
|
+
* `isUnlockingWallet` booleans, and the client emits `wallet-creating` and
|
|
694
|
+
* `wallet-unlocking` events. If you suppress it, show something of your own —
|
|
695
|
+
* a silent multi-second pause reads as a broken page.
|
|
685
696
|
*/
|
|
686
|
-
|
|
697
|
+
showStatusOverlay?: boolean;
|
|
687
698
|
/**
|
|
688
|
-
*
|
|
689
|
-
*
|
|
690
|
-
*
|
|
691
|
-
*
|
|
699
|
+
* Offer to save a recovery-share file at signup. **Default false** since
|
|
700
|
+
* 2.7.4 — opt in explicitly with `true`.
|
|
701
|
+
*
|
|
702
|
+
* Server-assisted provisioning now covers the new-device case (wallets are
|
|
703
|
+
* enrolled at creation and repair themselves on unlock), so for most apps
|
|
704
|
+
* this dialog is a password prompt during onboarding that buys nothing. Turn
|
|
705
|
+
* it on if you want users to hold an offline fallback that works when Decane
|
|
706
|
+
* is unreachable.
|
|
692
707
|
*/
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
708
|
+
offerRecoveryAtSignup?: boolean;
|
|
709
|
+
/** Ask the user whether they want a recovery share and, if so, a password for it. */
|
|
710
|
+
onRecoveryShareOffer?: (addresses: {
|
|
711
|
+
evmAddress: string;
|
|
712
|
+
solanaAddress: string;
|
|
713
|
+
}) => Promise<{
|
|
714
|
+
wants: boolean;
|
|
715
|
+
password: string;
|
|
716
|
+
passwordHint?: string;
|
|
717
|
+
}>;
|
|
718
|
+
/** Hand the built file + suggested filename to the app, which owns the download. */
|
|
719
|
+
onRecoveryFileReady?: (file: RecoveryShareFile, filename: string) => Promise<void>;
|
|
702
720
|
/**
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
721
|
+
* Prompt for a recovery-share file (and its password) during recovery.
|
|
722
|
+
* Return null to cancel. **Without this, a user who needs the recovery-file
|
|
723
|
+
* path fails immediately with NewDeviceError** — there is nowhere to ask them
|
|
724
|
+
* for the file.
|
|
707
725
|
*/
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
balance: BalanceResult | null;
|
|
713
|
-
}>>;
|
|
726
|
+
promptForRecoveryFile?: () => Promise<{
|
|
727
|
+
value: unknown;
|
|
728
|
+
getPassword: () => Promise<string | null>;
|
|
729
|
+
} | null>;
|
|
714
730
|
/**
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
*
|
|
718
|
-
* to the user — this does not download anything itself).
|
|
731
|
+
* Every successful recovery/rotation invalidates the previous recovery file,
|
|
732
|
+
* so this must prompt for a new password and capture the replacement.
|
|
733
|
+
* Required before recovery can run at all.
|
|
719
734
|
*/
|
|
720
|
-
|
|
735
|
+
onRecoveryRotated?: (addresses: {
|
|
736
|
+
evmAddress: string;
|
|
737
|
+
solanaAddress: string;
|
|
738
|
+
}) => Promise<{
|
|
721
739
|
password: string;
|
|
722
740
|
passwordHint?: string;
|
|
723
|
-
}
|
|
741
|
+
}>;
|
|
742
|
+
/** Recovery stage callbacks, for your own progress UI. */
|
|
743
|
+
onRecoveryProgress?: (event: RecoveryProgress) => void;
|
|
724
744
|
/**
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
*
|
|
728
|
-
*
|
|
745
|
+
* Require a fresh WebAuthn assertion for every signature rather than letting
|
|
746
|
+
* an unlocked session sign freely until it expires. Enforced inside the TEE.
|
|
747
|
+
*
|
|
748
|
+
* Does not change the session lifetime — the session stays warm (no
|
|
749
|
+
* re-attestation, no re-auth) and authority is re-proven per signature
|
|
750
|
+
* instead. Default false. Needs a passkey; PIN-only wallets have no
|
|
751
|
+
* authenticator to assert with. See SocialConfig's counterpart in
|
|
752
|
+
* social/types.ts for the full caveats.
|
|
729
753
|
*/
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
754
|
+
requireAssertionPerSignature?: boolean;
|
|
755
|
+
/**
|
|
756
|
+
* Sign in with a token from your own auth system (Auth0, Clerk, Firebase,
|
|
757
|
+
* Cognito, or your own backend) — surfaced as a button in the built-in
|
|
758
|
+
* WalletSelector / SocialWalletModal UI, alongside Google and email.
|
|
759
|
+
* getToken() runs when the user clicks the button; wire it to however you
|
|
760
|
+
* already obtain a token from your auth system (e.g. after your own login
|
|
761
|
+
* flow completes). Configure the issuer and JWKS URL for this token
|
|
762
|
+
* against your project in the dashboard first. `providerId` is only
|
|
763
|
+
* needed when the project has more than one custom provider configured.
|
|
764
|
+
*/
|
|
765
|
+
customAuth?: {
|
|
766
|
+
label: string;
|
|
767
|
+
providerId?: string;
|
|
768
|
+
getToken: () => Promise<string>;
|
|
769
|
+
};
|
|
746
770
|
}
|
|
747
|
-
interface
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
771
|
+
interface DecaneConfig {
|
|
772
|
+
appId: string;
|
|
773
|
+
chains?: ChainDescriptor[];
|
|
774
|
+
supportedChainIds?: string[];
|
|
775
|
+
networks?: "evm" | "solana" | "tron" | "bitcoin" | "all";
|
|
776
|
+
defaultChain?: string;
|
|
777
|
+
theme?: "light" | "dark" | "auto";
|
|
778
|
+
mode?: ConnectMode;
|
|
779
|
+
social?: SocialConfig;
|
|
753
780
|
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
*
|
|
762
|
-
* Every field is optional because providers differ in what they release, and a
|
|
763
|
-
* user can withhold most of it. Email sign-in returns an empty profile.
|
|
764
|
-
*/
|
|
765
|
-
interface AuthProfile {
|
|
766
|
-
name?: string;
|
|
767
|
-
email?: string;
|
|
768
|
-
picture?: string;
|
|
781
|
+
interface EIP1193Provider {
|
|
782
|
+
request(args: {
|
|
783
|
+
method: string;
|
|
784
|
+
params?: unknown[];
|
|
785
|
+
}): Promise<unknown>;
|
|
786
|
+
on(event: string, handler: (...args: unknown[]) => void): void;
|
|
787
|
+
removeListener(event: string, handler: (...args: unknown[]) => void): void;
|
|
769
788
|
}
|
|
770
|
-
interface
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
789
|
+
interface StandardWallet {
|
|
790
|
+
name: string;
|
|
791
|
+
icon: string;
|
|
792
|
+
features: Record<string, unknown>;
|
|
793
|
+
accounts: StandardWalletAccount[];
|
|
794
|
+
}
|
|
795
|
+
interface StandardWalletAccount {
|
|
796
|
+
address: string;
|
|
797
|
+
publicKey: Uint8Array;
|
|
798
|
+
chains: string[];
|
|
799
|
+
}
|
|
800
|
+
interface TronProvider {
|
|
801
|
+
request(args: {
|
|
802
|
+
method: string;
|
|
803
|
+
params?: unknown[] | Record<string, unknown>;
|
|
804
|
+
}): Promise<unknown>;
|
|
805
|
+
on(event: string, handler: (...args: unknown[]) => void): void;
|
|
806
|
+
removeListener(event: string, handler: (...args: unknown[]) => void): void;
|
|
807
|
+
}
|
|
808
|
+
interface BitcoinProvider {
|
|
809
|
+
requestAccounts(): Promise<string[] | Array<{
|
|
810
|
+
address: string;
|
|
811
|
+
}>>;
|
|
812
|
+
getAccounts?(): Promise<string[] | Array<{
|
|
813
|
+
address: string;
|
|
814
|
+
}>>;
|
|
815
|
+
signMessage(message: string, ...args: unknown[]): Promise<string>;
|
|
816
|
+
sendBitcoin?(toAddress: string, satoshis: number, options?: unknown): Promise<string>;
|
|
817
|
+
send?(params: unknown): Promise<string>;
|
|
818
|
+
signPsbt?(psbtHex: string, options?: unknown): Promise<string>;
|
|
819
|
+
on?(event: string, handler: (...args: unknown[]) => void): void;
|
|
776
820
|
}
|
|
777
821
|
|
|
822
|
+
declare function createDecane(config: DecaneConfig): DecaneProvider;
|
|
823
|
+
|
|
778
824
|
declare function createDecaneConnect(config: DecaneConnectConfig): Promise<DecaneConnect>;
|
|
779
825
|
|
|
780
826
|
/**
|