decane-connect-kit 2.4.0 → 2.6.0
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 +425 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +182 -7
- package/dist/index.d.ts +182 -7
- package/dist/index.js +423 -5
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -49,12 +49,13 @@ __export(errors_exports, {
|
|
|
49
49
|
RecoveryWalletMismatchError: () => RecoveryWalletMismatchError,
|
|
50
50
|
SessionExpiredError: () => SessionExpiredError,
|
|
51
51
|
ShareCorruptedError: () => ShareCorruptedError,
|
|
52
|
+
StaleDeviceShareError: () => StaleDeviceShareError,
|
|
52
53
|
UnlockRequiredError: () => UnlockRequiredError,
|
|
53
54
|
UserCancelledError: () => UserCancelledError,
|
|
54
55
|
WebAuthnNotSupportedError: () => WebAuthnNotSupportedError,
|
|
55
56
|
WrongPasswordError: () => WrongPasswordError
|
|
56
57
|
});
|
|
57
|
-
var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, NewDeviceError, PromptPinNotConfiguredError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
|
|
58
|
+
var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError;
|
|
58
59
|
var init_errors = __esm({
|
|
59
60
|
"src/social/errors.ts"() {
|
|
60
61
|
"use strict";
|
|
@@ -130,6 +131,15 @@ var init_errors = __esm({
|
|
|
130
131
|
super("NEW_DEVICE", "No device share found. Re-authenticate to set up this device.");
|
|
131
132
|
}
|
|
132
133
|
};
|
|
134
|
+
StaleDeviceShareError = class extends DecaneConnectError {
|
|
135
|
+
constructor() {
|
|
136
|
+
super(
|
|
137
|
+
"STALE_DEVICE_SHARE",
|
|
138
|
+
"This device\u2019s wallet share is from a superseded share set (likely rotated from another device) and no longer matches this account. Reconnect to recover a fresh share.",
|
|
139
|
+
true
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
133
143
|
PromptPinNotConfiguredError = class extends DecaneConnectError {
|
|
134
144
|
constructor() {
|
|
135
145
|
super("PROMPT_PIN_NOT_CONFIGURED", "Passkey unavailable and no promptPin callback was provided in config");
|
|
@@ -200,6 +210,7 @@ __export(index_exports, {
|
|
|
200
210
|
SessionExpiredError: () => SessionExpiredError,
|
|
201
211
|
ShareCorruptedError: () => ShareCorruptedError,
|
|
202
212
|
SocialWalletModal: () => SocialWalletModal,
|
|
213
|
+
StaleDeviceShareError: () => StaleDeviceShareError,
|
|
203
214
|
UnlockRequiredError: () => UnlockRequiredError,
|
|
204
215
|
UserCancelledError: () => UserCancelledError,
|
|
205
216
|
WalletSelector: () => WalletSelector,
|
|
@@ -208,6 +219,7 @@ __export(index_exports, {
|
|
|
208
219
|
createDecane: () => createDecane,
|
|
209
220
|
createDecaneConnect: () => createDecaneConnect,
|
|
210
221
|
createEthereumProvider: () => createEthereumProvider,
|
|
222
|
+
loginWithKingsChatPopup: () => loginWithKingsChatPopup,
|
|
211
223
|
startEmailAuth: () => startEmailAuth,
|
|
212
224
|
useChainSwitch: () => useChainSwitch,
|
|
213
225
|
useDecane: () => useDecane,
|
|
@@ -2030,6 +2042,32 @@ var ApiClient = class {
|
|
|
2030
2042
|
async getGoogleInitUrl() {
|
|
2031
2043
|
return this._request("/auth/google/init", { method: "GET" });
|
|
2032
2044
|
}
|
|
2045
|
+
/**
|
|
2046
|
+
* Exchange a Google ID token the app already holds for a Decane session.
|
|
2047
|
+
* Resolves to the SAME identity as the redirect flow, so one Google account
|
|
2048
|
+
* means one wallet across web and mobile.
|
|
2049
|
+
*/
|
|
2050
|
+
async authGoogleToken(idToken) {
|
|
2051
|
+
return this._request("/auth/google/token", {
|
|
2052
|
+
method: "POST",
|
|
2053
|
+
body: JSON.stringify({ idToken })
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
/** The project's KingsChat clientId, so the dApp never has to hardcode it. */
|
|
2057
|
+
async getKingsChatConfig() {
|
|
2058
|
+
return this._request("/auth/kingschat/config", { method: "GET" });
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* Exchange a KingsChat access token for a Decane session. The backend spends
|
|
2062
|
+
* the token against KingsChat's own API to establish the identity — it is
|
|
2063
|
+
* never trusted on its face, and never stored.
|
|
2064
|
+
*/
|
|
2065
|
+
async authKingsChat(accessToken) {
|
|
2066
|
+
return this._request("/auth/kingschat", {
|
|
2067
|
+
method: "POST",
|
|
2068
|
+
body: JSON.stringify({ accessToken })
|
|
2069
|
+
});
|
|
2070
|
+
}
|
|
2033
2071
|
async authEmailStart(email) {
|
|
2034
2072
|
await this._request("/auth/email/start", {
|
|
2035
2073
|
method: "POST",
|
|
@@ -2064,6 +2102,21 @@ var ApiClient = class {
|
|
|
2064
2102
|
})
|
|
2065
2103
|
});
|
|
2066
2104
|
}
|
|
2105
|
+
// ── Transaction history ───────────────────────────────────────────────────
|
|
2106
|
+
async recordTransaction(jwt, tx) {
|
|
2107
|
+
const body = await this._request("/transactions", {
|
|
2108
|
+
method: "POST",
|
|
2109
|
+
headers: { Authorization: `Bearer ${jwt}` },
|
|
2110
|
+
body: JSON.stringify(tx)
|
|
2111
|
+
});
|
|
2112
|
+
return body.transaction;
|
|
2113
|
+
}
|
|
2114
|
+
async getTransactions(jwt, limit = 50) {
|
|
2115
|
+
const body = await this._request(`/transactions?limit=${encodeURIComponent(String(limit))}`, {
|
|
2116
|
+
headers: { Authorization: `Bearer ${jwt}` }
|
|
2117
|
+
});
|
|
2118
|
+
return body.transactions;
|
|
2119
|
+
}
|
|
2067
2120
|
// ── WebAuthn registration (additive to the PRF-only passkey flow) ─────────
|
|
2068
2121
|
async getWebAuthnRegisterOptions(jwt, rpId, rpName) {
|
|
2069
2122
|
return this._request(`/webauthn/register-options?rpId=${encodeURIComponent(rpId)}&rpName=${encodeURIComponent(rpName)}`, {
|
|
@@ -2339,6 +2392,13 @@ var TeeClient = class {
|
|
|
2339
2392
|
requireAssertionPerSignature
|
|
2340
2393
|
})
|
|
2341
2394
|
});
|
|
2395
|
+
if (res.status === 403) {
|
|
2396
|
+
const body2 = await res.json().catch(() => ({}));
|
|
2397
|
+
if (body2?.error === "share_mismatch") {
|
|
2398
|
+
const { StaleDeviceShareError: StaleDeviceShareError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
2399
|
+
throw new StaleDeviceShareError2();
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2342
2402
|
if (!res.ok) throw new Error("session open failed");
|
|
2343
2403
|
const body = await res.json();
|
|
2344
2404
|
this.handle = body.handle;
|
|
@@ -2398,6 +2458,45 @@ var TeeClient = class {
|
|
|
2398
2458
|
}
|
|
2399
2459
|
return { challengeId, assertion };
|
|
2400
2460
|
}
|
|
2461
|
+
/**
|
|
2462
|
+
* Enrol this wallet for server-assisted provisioning by handing the enclave
|
|
2463
|
+
* the recovery share to seal.
|
|
2464
|
+
*
|
|
2465
|
+
* After this, a new device gets a working share from login alone — no passkey
|
|
2466
|
+
* sync, no recovery file. The enclave seals the share under a key only it can
|
|
2467
|
+
* derive, so the backend stores ciphertext it cannot read; but the enclave
|
|
2468
|
+
* then holds two of three shares and can reconstruct on its own. That is the
|
|
2469
|
+
* trade this call makes, which is why it is opt-out rather than implicit.
|
|
2470
|
+
*/
|
|
2471
|
+
async enrolAuthShare(jwt, recoveryShare) {
|
|
2472
|
+
await this.ensureAttested();
|
|
2473
|
+
const res = await fetch(`${this.teeUrl}/signer/auth-share`, {
|
|
2474
|
+
method: "POST",
|
|
2475
|
+
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2476
|
+
body: JSON.stringify({ share: bytesToBase64(recoveryShare) })
|
|
2477
|
+
});
|
|
2478
|
+
if (!res.ok) throw new Error("auth share enrolment failed");
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* Ask the enclave for a fresh device share for this authenticated user.
|
|
2482
|
+
* Returns null when the wallet was never enrolled — the signal to fall back
|
|
2483
|
+
* to passkey sync or the recovery file rather than fail.
|
|
2484
|
+
*
|
|
2485
|
+
* Every successful call re-splits the set, so any share this device or any
|
|
2486
|
+
* other held is now dead. Intentional: a leaked device share stops working the
|
|
2487
|
+
* next time the user signs in anywhere.
|
|
2488
|
+
*/
|
|
2489
|
+
async provisionDeviceShare(jwt) {
|
|
2490
|
+
await this.ensureAttested();
|
|
2491
|
+
const res = await fetch(`${this.teeUrl}/signer/provision`, {
|
|
2492
|
+
method: "POST",
|
|
2493
|
+
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" }
|
|
2494
|
+
});
|
|
2495
|
+
if (res.status === 409) return null;
|
|
2496
|
+
if (!res.ok) throw new Error("device share provisioning failed");
|
|
2497
|
+
const body = await res.json();
|
|
2498
|
+
return base64ToBytes(body.deviceShare);
|
|
2499
|
+
}
|
|
2401
2500
|
/** Voluntary rotation — e.g. after a suspected device compromise, or to invalidate an old recovery file. */
|
|
2402
2501
|
async rotateShares(jwt) {
|
|
2403
2502
|
if (!this.handle) throw new Error("no session");
|
|
@@ -2784,6 +2883,79 @@ async function verifyEmailCode(api, email, code) {
|
|
|
2784
2883
|
return api.authEmailVerify(email, code);
|
|
2785
2884
|
}
|
|
2786
2885
|
|
|
2886
|
+
// src/social/auth/kingschat.ts
|
|
2887
|
+
init_errors();
|
|
2888
|
+
var KINGSCHAT_AUTH_ORIGIN = "https://accounts.kingsch.at";
|
|
2889
|
+
function readTokens(data) {
|
|
2890
|
+
if (!data || typeof data !== "object") return null;
|
|
2891
|
+
const d = data;
|
|
2892
|
+
const accessToken = d.accessToken ?? d.access_token;
|
|
2893
|
+
if (typeof accessToken !== "string" || !accessToken) return null;
|
|
2894
|
+
const refreshToken = d.refreshToken ?? d.refresh_token;
|
|
2895
|
+
const expires = d.expiresInMillis ?? d.expires_in_millis;
|
|
2896
|
+
return {
|
|
2897
|
+
accessToken,
|
|
2898
|
+
refreshToken: typeof refreshToken === "string" ? refreshToken : void 0,
|
|
2899
|
+
expiresInMillis: typeof expires === "number" ? expires : void 0
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
function buildAuthUrl(clientId, scopes) {
|
|
2903
|
+
const url = new URL(KINGSCHAT_AUTH_ORIGIN);
|
|
2904
|
+
url.searchParams.set("client_id", clientId);
|
|
2905
|
+
url.searchParams.set("scopes", JSON.stringify(scopes));
|
|
2906
|
+
url.searchParams.set("redirect_uri", window.location.origin);
|
|
2907
|
+
url.searchParams.set("post_message", "1");
|
|
2908
|
+
return url.toString();
|
|
2909
|
+
}
|
|
2910
|
+
function loginWithKingsChatPopup(opts) {
|
|
2911
|
+
const scopes = opts.scopes ?? ["send_chat_message"];
|
|
2912
|
+
const popup = window.open(
|
|
2913
|
+
buildAuthUrl(opts.clientId, scopes),
|
|
2914
|
+
"decane-kingschat",
|
|
2915
|
+
"width=480,height=720,menubar=no,toolbar=no"
|
|
2916
|
+
);
|
|
2917
|
+
if (!popup) {
|
|
2918
|
+
throw new CallSequenceError(
|
|
2919
|
+
"The KingsChat sign-in popup was blocked. Call connectWithKingsChat() directly from a click handler."
|
|
2920
|
+
);
|
|
2921
|
+
}
|
|
2922
|
+
return new Promise((resolve, reject) => {
|
|
2923
|
+
let settled = false;
|
|
2924
|
+
const finish = (fn) => {
|
|
2925
|
+
if (settled) return;
|
|
2926
|
+
settled = true;
|
|
2927
|
+
window.removeEventListener("message", onMessage);
|
|
2928
|
+
clearInterval(closedPoll);
|
|
2929
|
+
clearTimeout(timeout);
|
|
2930
|
+
try {
|
|
2931
|
+
popup.close();
|
|
2932
|
+
} catch {
|
|
2933
|
+
}
|
|
2934
|
+
fn();
|
|
2935
|
+
};
|
|
2936
|
+
const onMessage = (event) => {
|
|
2937
|
+
if (event.origin !== KINGSCHAT_AUTH_ORIGIN) return;
|
|
2938
|
+
const data = event.data;
|
|
2939
|
+
if (data && typeof data === "object" && data.error) {
|
|
2940
|
+
finish(() => reject(new CallSequenceError(`KingsChat sign-in failed: ${String(data.error)}`)));
|
|
2941
|
+
return;
|
|
2942
|
+
}
|
|
2943
|
+
const tokens2 = readTokens(event.data);
|
|
2944
|
+
if (tokens2) finish(() => resolve(tokens2));
|
|
2945
|
+
};
|
|
2946
|
+
window.addEventListener("message", onMessage);
|
|
2947
|
+
const closedPoll = setInterval(() => {
|
|
2948
|
+
if (popup.closed) finish(() => reject(new UserCancelledError()));
|
|
2949
|
+
}, 400);
|
|
2950
|
+
const timeout = setTimeout(
|
|
2951
|
+
() => finish(
|
|
2952
|
+
() => reject(new CallSequenceError("KingsChat sign-in timed out before returning a token."))
|
|
2953
|
+
),
|
|
2954
|
+
opts.timeoutMs ?? 5 * 6e4
|
|
2955
|
+
);
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2787
2959
|
// src/social/signers/evm.ts
|
|
2788
2960
|
var import_ethers2 = require("ethers");
|
|
2789
2961
|
async function signEvmTransaction(tee, chain, tx, jwt) {
|
|
@@ -3146,7 +3318,7 @@ async function recoverDeviceShare(input) {
|
|
|
3146
3318
|
prfSalt: backup.prfSalt,
|
|
3147
3319
|
version: 1
|
|
3148
3320
|
});
|
|
3149
|
-
return deviceShare;
|
|
3321
|
+
return { deviceShare, flow: "passkey-sync" };
|
|
3150
3322
|
} catch (e) {
|
|
3151
3323
|
input.onProgress?.({
|
|
3152
3324
|
type: "passkey-failed",
|
|
@@ -3174,7 +3346,7 @@ async function recoverDeviceShare(input) {
|
|
|
3174
3346
|
input.onProgress?.({ type: "rotated", shareSetVersion: result.shareSetVersion });
|
|
3175
3347
|
await input.onNewRecoveryShare?.(result.recoveryShare, result.shareSetVersion);
|
|
3176
3348
|
zeroize(result.recoveryShare);
|
|
3177
|
-
return result.deviceShare;
|
|
3349
|
+
return { deviceShare: result.deviceShare, flow: "recovery-file" };
|
|
3178
3350
|
}
|
|
3179
3351
|
|
|
3180
3352
|
// src/social/recovery/portableBackup.ts
|
|
@@ -3292,6 +3464,11 @@ async function createDecaneConnect(config) {
|
|
|
3292
3464
|
if (!config.apiKey) throw new Error("decane-connect-kit: apiKey is required");
|
|
3293
3465
|
if (!config.chains?.length)
|
|
3294
3466
|
throw new Error("decane-connect-kit: at least one chain is required");
|
|
3467
|
+
if (config.rotateOnNewDeviceRecovery && !config.onRecoveryRotated) {
|
|
3468
|
+
throw new Error(
|
|
3469
|
+
"decane-connect-kit: rotateOnNewDeviceRecovery requires an onRecoveryRotated callback \u2014 rotating on device join invalidates the user's existing recovery file, and the replacement must be saved."
|
|
3470
|
+
);
|
|
3471
|
+
}
|
|
3295
3472
|
const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE;
|
|
3296
3473
|
const durationMs = (config.sessionDurationMinutes ?? DEFAULT_SESSION_MINUTES) * 6e4;
|
|
3297
3474
|
const rpId = config.rpId ?? (typeof window !== "undefined" ? window.location.hostname : "localhost");
|
|
@@ -3311,6 +3488,7 @@ async function createDecaneConnect(config) {
|
|
|
3311
3488
|
let persisted = loadPersisted(PERSIST_KEY);
|
|
3312
3489
|
let ethProvider = null;
|
|
3313
3490
|
const persistSession = config.persistSession !== false;
|
|
3491
|
+
const serverAssistedRecovery = config.serverAssistedRecovery !== false;
|
|
3314
3492
|
const SESSION_KEY = sessionPersistKey(config.apiKey);
|
|
3315
3493
|
function persistLiveSession() {
|
|
3316
3494
|
if (!persistSession) return;
|
|
@@ -3536,6 +3714,17 @@ async function createDecaneConnect(config) {
|
|
|
3536
3714
|
console.warn("decane-connect-kit: recovery share offer failed or was skipped.", e);
|
|
3537
3715
|
}
|
|
3538
3716
|
}
|
|
3717
|
+
if (serverAssistedRecovery) {
|
|
3718
|
+
try {
|
|
3719
|
+
const tee = new TeeClient(teeUrl);
|
|
3720
|
+
await tee.enrolAuthShare(jwt, shareSet.recovery);
|
|
3721
|
+
} catch (e) {
|
|
3722
|
+
console.warn(
|
|
3723
|
+
"decane-connect-kit: could not enrol this wallet for server-assisted recovery; a recovery file will be required on a new device.",
|
|
3724
|
+
e
|
|
3725
|
+
);
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3539
3728
|
zeroize(shareSet.recovery);
|
|
3540
3729
|
return addresses;
|
|
3541
3730
|
}
|
|
@@ -3544,13 +3733,36 @@ async function createDecaneConnect(config) {
|
|
|
3544
3733
|
const recordedAddresses = rawAddresses.evm && rawAddresses.solana ? { evm: rawAddresses.evm, solana: rawAddresses.solana, tron: rawAddresses.tron ?? evmToTronAddress2(rawAddresses.evm) } : null;
|
|
3545
3734
|
const stored = await storage.getShare(userId);
|
|
3546
3735
|
let deviceShare;
|
|
3736
|
+
let joinedViaPasskeySync = false;
|
|
3547
3737
|
if (!stored) {
|
|
3738
|
+
if (serverAssistedRecovery) {
|
|
3739
|
+
try {
|
|
3740
|
+
const tee = new TeeClient(teeUrl);
|
|
3741
|
+
const provisioned = await tee.provisionDeviceShare(jwt);
|
|
3742
|
+
if (provisioned) {
|
|
3743
|
+
await registerPasskeyAndBackup(userId, jwt, provisioned).catch(() => {
|
|
3744
|
+
});
|
|
3745
|
+
let addrs;
|
|
3746
|
+
try {
|
|
3747
|
+
addrs = await session.start(provisioned, jwt, recordedAddresses);
|
|
3748
|
+
} finally {
|
|
3749
|
+
zeroize(provisioned);
|
|
3750
|
+
}
|
|
3751
|
+
return addrs;
|
|
3752
|
+
}
|
|
3753
|
+
} catch (e) {
|
|
3754
|
+
console.warn(
|
|
3755
|
+
"decane-connect-kit: server-assisted provisioning unavailable; falling back to passkey/recovery-file recovery.",
|
|
3756
|
+
e
|
|
3757
|
+
);
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3548
3760
|
if (!config.onRecoveryRotated) {
|
|
3549
3761
|
throw new CallSequenceError(
|
|
3550
3762
|
"Recovery rotates the share set and issues a new recovery file, but no onRecoveryRotated callback is configured to save it. Configure onRecoveryRotated before allowing recovery."
|
|
3551
3763
|
);
|
|
3552
3764
|
}
|
|
3553
|
-
|
|
3765
|
+
const recovered = await recoverDeviceShare({
|
|
3554
3766
|
userId,
|
|
3555
3767
|
jwt,
|
|
3556
3768
|
rpId,
|
|
@@ -3568,6 +3780,8 @@ async function createDecaneConnect(config) {
|
|
|
3568
3780
|
await api.markRecoveryShareSaved(jwt);
|
|
3569
3781
|
}
|
|
3570
3782
|
});
|
|
3783
|
+
deviceShare = recovered.deviceShare;
|
|
3784
|
+
joinedViaPasskeySync = recovered.flow === "passkey-sync";
|
|
3571
3785
|
if (!await storage.getShare(userId) && isPasskeySupported()) {
|
|
3572
3786
|
await registerPasskeyAndBackup(userId, jwt, deviceShare);
|
|
3573
3787
|
}
|
|
@@ -3583,15 +3797,66 @@ async function createDecaneConnect(config) {
|
|
|
3583
3797
|
throw stored.unlockMethod === "pin" ? new InvalidPinError() : new ShareCorruptedError();
|
|
3584
3798
|
}
|
|
3585
3799
|
}
|
|
3586
|
-
|
|
3800
|
+
let addresses;
|
|
3801
|
+
try {
|
|
3802
|
+
addresses = await session.start(deviceShare, jwt, recordedAddresses);
|
|
3803
|
+
} catch (e) {
|
|
3804
|
+
if (e instanceof StaleDeviceShareError) {
|
|
3805
|
+
zeroize(deviceShare);
|
|
3806
|
+
await storage.deleteShare(userId);
|
|
3807
|
+
if (stored) return returningUserUnlock(userId, jwt);
|
|
3808
|
+
} else {
|
|
3809
|
+
zeroize(deviceShare);
|
|
3810
|
+
}
|
|
3811
|
+
throw e;
|
|
3812
|
+
}
|
|
3587
3813
|
zeroize(deviceShare);
|
|
3588
3814
|
if (recordedAddresses && recordedAddresses.evm.toLowerCase() !== addresses.evm.toLowerCase()) {
|
|
3589
3815
|
console.warn(
|
|
3590
3816
|
`decane-connect-kit: recorded EVM address (${recordedAddresses.evm}) does not match the signing key (${addresses.evm}). Using the signing key's address; the record has been corrected.`
|
|
3591
3817
|
);
|
|
3592
3818
|
}
|
|
3819
|
+
if (joinedViaPasskeySync && config.rotateOnNewDeviceRecovery) {
|
|
3820
|
+
await rotateForNewDevice(userId, jwt);
|
|
3821
|
+
}
|
|
3593
3822
|
return addresses;
|
|
3594
3823
|
}
|
|
3824
|
+
async function rotateForNewDevice(userId, jwt) {
|
|
3825
|
+
const tee = session.requireActive();
|
|
3826
|
+
const result = await tee.rotateShares(jwt);
|
|
3827
|
+
try {
|
|
3828
|
+
await persistRotatedDeviceShare(userId, result.deviceShare);
|
|
3829
|
+
const refreshed = await storage.getShare(userId);
|
|
3830
|
+
if (refreshed?.unlockMethod === "passkey" && refreshed.credentialId && refreshed.prfSalt) {
|
|
3831
|
+
await api.putRecoveryBackup(jwt, {
|
|
3832
|
+
wrappedDeviceShare: refreshed.wrappedDeviceShare,
|
|
3833
|
+
iv: refreshed.iv,
|
|
3834
|
+
unlockMethod: "passkey",
|
|
3835
|
+
credentialId: refreshed.credentialId,
|
|
3836
|
+
prfSalt: refreshed.prfSalt
|
|
3837
|
+
}).catch((e) => {
|
|
3838
|
+
console.warn("decane-connect-kit: backup refresh after device rotation failed; the next new device will need the recovery file.", e);
|
|
3839
|
+
});
|
|
3840
|
+
}
|
|
3841
|
+
const addrs = await deriveAddressesFromShares(result.deviceShare, result.recoveryShare);
|
|
3842
|
+
const { password, passwordHint } = await config.onRecoveryRotated({
|
|
3843
|
+
evmAddress: addrs.evm,
|
|
3844
|
+
solanaAddress: addrs.solana
|
|
3845
|
+
});
|
|
3846
|
+
const file = await buildRecoveryShareFile(
|
|
3847
|
+
result.recoveryShare,
|
|
3848
|
+
password,
|
|
3849
|
+
addrs,
|
|
3850
|
+
result.shareSetVersion,
|
|
3851
|
+
passwordHint
|
|
3852
|
+
);
|
|
3853
|
+
await config.onRecoveryFileReady?.(file, recoveryShareFileName(addrs.evm));
|
|
3854
|
+
await api.markRecoveryShareSaved(jwt);
|
|
3855
|
+
} finally {
|
|
3856
|
+
zeroize(result.deviceShare);
|
|
3857
|
+
zeroize(result.recoveryShare);
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3595
3860
|
async function passkeyLoginCandidate() {
|
|
3596
3861
|
if (!persisted?.userId || !isPasskeySupported()) return null;
|
|
3597
3862
|
const stored = await storage.getShare(persisted.userId);
|
|
@@ -3666,6 +3931,7 @@ async function createDecaneConnect(config) {
|
|
|
3666
3931
|
const method = config.authMethods[0];
|
|
3667
3932
|
if (!method) throw new CallSequenceError("No authMethods configured");
|
|
3668
3933
|
if (method === "google") return client.connectWithGoogle();
|
|
3934
|
+
if (method === "kingschat") return client.connectWithKingsChat();
|
|
3669
3935
|
if (method === "email")
|
|
3670
3936
|
throw new CallSequenceError(
|
|
3671
3937
|
"Use connectWithEmail(email) for email auth"
|
|
@@ -3695,6 +3961,25 @@ async function createDecaneConnect(config) {
|
|
|
3695
3961
|
return new Promise(() => {
|
|
3696
3962
|
});
|
|
3697
3963
|
},
|
|
3964
|
+
async connectWithGoogleToken(idToken) {
|
|
3965
|
+
if (!idToken) throw new CallSequenceError("connectWithGoogleToken requires an ID token");
|
|
3966
|
+
return handleAuthResult(await api.authGoogleToken(idToken));
|
|
3967
|
+
},
|
|
3968
|
+
async connectWithKingsChat() {
|
|
3969
|
+
const { clientId } = await api.getKingsChatConfig();
|
|
3970
|
+
const tokens2 = await loginWithKingsChatPopup({
|
|
3971
|
+
clientId,
|
|
3972
|
+
scopes: config.kingsChatScopes
|
|
3973
|
+
});
|
|
3974
|
+
return client.connectWithKingsChatToken(tokens2.accessToken);
|
|
3975
|
+
},
|
|
3976
|
+
async connectWithKingsChatToken(accessToken) {
|
|
3977
|
+
if (!accessToken) {
|
|
3978
|
+
throw new CallSequenceError("connectWithKingsChatToken requires an access token");
|
|
3979
|
+
}
|
|
3980
|
+
const result = await api.authKingsChat(accessToken);
|
|
3981
|
+
return handleAuthResult(result);
|
|
3982
|
+
},
|
|
3698
3983
|
async connectWithToken(token, opts) {
|
|
3699
3984
|
if (!token) throw new CallSequenceError("connectWithToken requires a token");
|
|
3700
3985
|
const result = await api.authExternal(token, opts?.providerId);
|
|
@@ -3806,6 +4091,16 @@ async function createDecaneConnect(config) {
|
|
|
3806
4091
|
};
|
|
3807
4092
|
const signedTx = await signEvmTransaction(tee, req.chain, tx, auth?.jwt);
|
|
3808
4093
|
const txResponse = await provider.broadcastTransaction(signedTx);
|
|
4094
|
+
if (auth?.jwt) {
|
|
4095
|
+
void api.recordTransaction(auth.jwt, {
|
|
4096
|
+
chain: req.chain,
|
|
4097
|
+
txHash: txResponse.hash,
|
|
4098
|
+
to: req.to,
|
|
4099
|
+
value: (req.value ?? 0n).toString(),
|
|
4100
|
+
kind: "send"
|
|
4101
|
+
}).catch(() => {
|
|
4102
|
+
});
|
|
4103
|
+
}
|
|
3809
4104
|
return txResponse.hash;
|
|
3810
4105
|
},
|
|
3811
4106
|
async signTypedData(req) {
|
|
@@ -3838,6 +4133,14 @@ async function createDecaneConnect(config) {
|
|
|
3838
4133
|
getAccessToken() {
|
|
3839
4134
|
return auth?.jwt ?? null;
|
|
3840
4135
|
},
|
|
4136
|
+
async recordTransaction(tx) {
|
|
4137
|
+
if (!auth?.jwt) throw new CallSequenceError("Not connected \u2014 call connect() first");
|
|
4138
|
+
return api.recordTransaction(auth.jwt, tx);
|
|
4139
|
+
},
|
|
4140
|
+
async getTransactionHistory(limit = 50) {
|
|
4141
|
+
if (!auth?.jwt) throw new CallSequenceError("Not connected \u2014 call connect() first");
|
|
4142
|
+
return api.getTransactions(auth.jwt, limit);
|
|
4143
|
+
},
|
|
3841
4144
|
getEthereumProvider(opts) {
|
|
3842
4145
|
if (!ethProvider) {
|
|
3843
4146
|
const firstEvm = config.chains.find((c) => c.startsWith("evm:"));
|
|
@@ -4449,6 +4752,7 @@ function WalletSelector({
|
|
|
4449
4752
|
mode = "wallets",
|
|
4450
4753
|
socialAuthMethods = ["google", "email"],
|
|
4451
4754
|
onGoogleSignIn,
|
|
4755
|
+
onKingsChatSignIn,
|
|
4452
4756
|
onEmailStart,
|
|
4453
4757
|
onEmailVerify,
|
|
4454
4758
|
customAuthLabel,
|
|
@@ -4526,6 +4830,18 @@ function WalletSelector({
|
|
|
4526
4830
|
setSocialLoad(false);
|
|
4527
4831
|
}
|
|
4528
4832
|
}
|
|
4833
|
+
async function handleKingsChatClick() {
|
|
4834
|
+
if (!onKingsChatSignIn) return;
|
|
4835
|
+
setSocialLoad(true);
|
|
4836
|
+
setSocialErr("");
|
|
4837
|
+
try {
|
|
4838
|
+
await onKingsChatSignIn();
|
|
4839
|
+
} catch (e) {
|
|
4840
|
+
setSocialErr(e.message);
|
|
4841
|
+
} finally {
|
|
4842
|
+
setSocialLoad(false);
|
|
4843
|
+
}
|
|
4844
|
+
}
|
|
4529
4845
|
async function handleCustomAuthClick() {
|
|
4530
4846
|
if (!onCustomAuthSignIn) return;
|
|
4531
4847
|
setSocialLoad(true);
|
|
@@ -4948,6 +5264,38 @@ function WalletSelector({
|
|
|
4948
5264
|
},
|
|
4949
5265
|
/* @__PURE__ */ import_react2.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none" }, /* @__PURE__ */ import_react2.default.createElement("path", { d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.875 2.684-6.615z", fill: "#4285F4" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z", fill: "#34A853" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z", fill: "#FBBC05" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 6.29C4.672 4.163 6.656 3.58 9 3.58z", fill: "#EA4335" })),
|
|
4950
5266
|
socialLoad ? "Redirecting\u2026" : "Continue with Google"
|
|
5267
|
+
), !passkeyFirst && socialAuthMethods.includes("kingschat") && onKingsChatSignIn && /* @__PURE__ */ import_react2.default.createElement(
|
|
5268
|
+
"button",
|
|
5269
|
+
{
|
|
5270
|
+
onClick: handleKingsChatClick,
|
|
5271
|
+
disabled: socialLoad,
|
|
5272
|
+
style: {
|
|
5273
|
+
display: "flex",
|
|
5274
|
+
alignItems: "center",
|
|
5275
|
+
justifyContent: "center",
|
|
5276
|
+
gap: 10,
|
|
5277
|
+
width: "100%",
|
|
5278
|
+
padding: "11px 16px",
|
|
5279
|
+
background: "var(--dc-surface)",
|
|
5280
|
+
border: "1px solid var(--dc-border)",
|
|
5281
|
+
borderRadius: 10,
|
|
5282
|
+
cursor: socialLoad ? "not-allowed" : "pointer",
|
|
5283
|
+
fontSize: 14,
|
|
5284
|
+
fontWeight: 600,
|
|
5285
|
+
color: "var(--dc-text)",
|
|
5286
|
+
fontFamily: "inherit",
|
|
5287
|
+
transition: "border-color 0.12s, background 0.12s",
|
|
5288
|
+
opacity: socialLoad ? 0.6 : 1
|
|
5289
|
+
},
|
|
5290
|
+
onMouseEnter: (e) => {
|
|
5291
|
+
if (!socialLoad) e.currentTarget.style.borderColor = "var(--dc-border-accent)";
|
|
5292
|
+
},
|
|
5293
|
+
onMouseLeave: (e) => {
|
|
5294
|
+
e.currentTarget.style.borderColor = "var(--dc-border)";
|
|
5295
|
+
}
|
|
5296
|
+
},
|
|
5297
|
+
/* @__PURE__ */ import_react2.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": "true" }, /* @__PURE__ */ import_react2.default.createElement("circle", { cx: "9", cy: "9", r: "9", fill: "var(--dc-accent)" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M5.5 4.5h1.9v3.6l3.1-3.6h2.3l-3.3 3.8 3.5 5.2h-2.3l-2.5-3.8-.8.9v2.9H5.5V4.5z", fill: "var(--dc-accent-text)" })),
|
|
5298
|
+
socialLoad ? "Waiting for KingsChat\u2026" : "Continue with KingsChat"
|
|
4951
5299
|
), !passkeyFirst && socialAuthMethods.includes("google") && socialAuthMethods.includes("email") && /* @__PURE__ */ import_react2.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10 } }, /* @__PURE__ */ import_react2.default.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } }), /* @__PURE__ */ import_react2.default.createElement("span", { style: { fontSize: 11, color: "var(--dc-text-muted)", whiteSpace: "nowrap" } }, "or continue with email"), /* @__PURE__ */ import_react2.default.createElement("div", { style: { flex: 1, height: 1, background: "var(--dc-border)" } })), !passkeyFirst && socialAuthMethods.includes("email") && (emailStep === "input" ? /* @__PURE__ */ import_react2.default.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ import_react2.default.createElement(
|
|
4952
5300
|
"input",
|
|
4953
5301
|
{
|
|
@@ -5194,6 +5542,7 @@ function AddressRow({
|
|
|
5194
5542
|
}
|
|
5195
5543
|
function SignInView({
|
|
5196
5544
|
onGoogleSignIn,
|
|
5545
|
+
onKingsChatSignIn,
|
|
5197
5546
|
onEmailStart,
|
|
5198
5547
|
onEmailVerify,
|
|
5199
5548
|
authMethods,
|
|
@@ -5205,6 +5554,7 @@ function SignInView({
|
|
|
5205
5554
|
onPasskeySignIn
|
|
5206
5555
|
}) {
|
|
5207
5556
|
const [googleLoading, setGoogleLoading] = (0, import_react3.useState)(false);
|
|
5557
|
+
const [kingsChatLoading, setKingsChatLoading] = (0, import_react3.useState)(false);
|
|
5208
5558
|
const [email, setEmail] = (0, import_react3.useState)("");
|
|
5209
5559
|
const [code, setCode] = (0, import_react3.useState)("");
|
|
5210
5560
|
const [emailSent, setEmailSent] = (0, import_react3.useState)(false);
|
|
@@ -5239,6 +5589,18 @@ function SignInView({
|
|
|
5239
5589
|
setGoogleLoading(false);
|
|
5240
5590
|
}
|
|
5241
5591
|
}
|
|
5592
|
+
async function handleKingsChat() {
|
|
5593
|
+
if (!onKingsChatSignIn) return;
|
|
5594
|
+
setError("");
|
|
5595
|
+
setKingsChatLoading(true);
|
|
5596
|
+
try {
|
|
5597
|
+
await onKingsChatSignIn();
|
|
5598
|
+
} catch (e) {
|
|
5599
|
+
setError(e.message);
|
|
5600
|
+
} finally {
|
|
5601
|
+
setKingsChatLoading(false);
|
|
5602
|
+
}
|
|
5603
|
+
}
|
|
5242
5604
|
async function handleEmailStart(e) {
|
|
5243
5605
|
e.preventDefault();
|
|
5244
5606
|
setError("");
|
|
@@ -5349,6 +5711,27 @@ function SignInView({
|
|
|
5349
5711
|
}
|
|
5350
5712
|
},
|
|
5351
5713
|
googleLoading ? "Redirecting\u2026" : "Continue with Google"
|
|
5714
|
+
), !passkeyFirst && authMethods.includes("kingschat") && onKingsChatSignIn && /* @__PURE__ */ import_react3.default.createElement(
|
|
5715
|
+
"button",
|
|
5716
|
+
{
|
|
5717
|
+
onClick: handleKingsChat,
|
|
5718
|
+
disabled: kingsChatLoading,
|
|
5719
|
+
style: {
|
|
5720
|
+
width: "100%",
|
|
5721
|
+
padding: "10px 0",
|
|
5722
|
+
marginBottom: 10,
|
|
5723
|
+
background: "var(--dc-surface)",
|
|
5724
|
+
color: "var(--dc-text)",
|
|
5725
|
+
border: "1px solid var(--dc-border)",
|
|
5726
|
+
borderRadius: 10,
|
|
5727
|
+
fontSize: 13,
|
|
5728
|
+
fontWeight: 700,
|
|
5729
|
+
cursor: kingsChatLoading ? "not-allowed" : "pointer",
|
|
5730
|
+
opacity: kingsChatLoading ? 0.7 : 1,
|
|
5731
|
+
fontFamily: "inherit"
|
|
5732
|
+
}
|
|
5733
|
+
},
|
|
5734
|
+
kingsChatLoading ? "Waiting for KingsChat\u2026" : "Continue with KingsChat"
|
|
5352
5735
|
), !passkeyFirst && authMethods.includes("email") && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, authMethods.includes("google") && /* @__PURE__ */ import_react3.default.createElement("div", { style: { textAlign: "center", color: "var(--dc-text-muted)", fontSize: 12, margin: "10px 0" } }, "\u2014 or \u2014"), !emailSent ? /* @__PURE__ */ import_react3.default.createElement("form", { onSubmit: handleEmailStart, style: { display: "flex", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement(
|
|
5353
5736
|
"input",
|
|
5354
5737
|
{
|
|
@@ -5522,6 +5905,7 @@ function SocialWalletModal({
|
|
|
5522
5905
|
onUnlock,
|
|
5523
5906
|
onDisconnect,
|
|
5524
5907
|
onGoogleSignIn,
|
|
5908
|
+
onKingsChatSignIn,
|
|
5525
5909
|
onEmailStart,
|
|
5526
5910
|
onEmailVerify,
|
|
5527
5911
|
authMethods = ["google", "email"],
|
|
@@ -5655,6 +6039,7 @@ function SocialWalletModal({
|
|
|
5655
6039
|
SignInView,
|
|
5656
6040
|
{
|
|
5657
6041
|
onGoogleSignIn,
|
|
6042
|
+
onKingsChatSignIn,
|
|
5658
6043
|
onEmailStart,
|
|
5659
6044
|
onEmailVerify,
|
|
5660
6045
|
authMethods,
|
|
@@ -5976,6 +6361,12 @@ function DecaneKit({ config, children }) {
|
|
|
5976
6361
|
if (!sdk) throw new Error("Social sign-in not configured");
|
|
5977
6362
|
await sdk.connectWithGoogle();
|
|
5978
6363
|
}, []);
|
|
6364
|
+
const connectWithKingsChat = (0, import_react5.useCallback)(async () => {
|
|
6365
|
+
const sdk = socialRef.current;
|
|
6366
|
+
if (!sdk) throw new Error("Social sign-in not configured");
|
|
6367
|
+
const result = await sdk.connectWithKingsChat();
|
|
6368
|
+
applyResult(result);
|
|
6369
|
+
}, [applyResult]);
|
|
5979
6370
|
const connectWithEmail = (0, import_react5.useCallback)(async (email) => {
|
|
5980
6371
|
const sdk = socialRef.current;
|
|
5981
6372
|
if (!sdk) throw new Error("Social sign-in not configured");
|
|
@@ -6055,6 +6446,16 @@ function DecaneKit({ config, children }) {
|
|
|
6055
6446
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
6056
6447
|
return sdk.signTronTransaction(rawDataHex);
|
|
6057
6448
|
}, []);
|
|
6449
|
+
const socialRecordTransaction = (0, import_react5.useCallback)(async (tx) => {
|
|
6450
|
+
const sdk = socialRef.current;
|
|
6451
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
6452
|
+
return sdk.recordTransaction(tx);
|
|
6453
|
+
}, []);
|
|
6454
|
+
const socialGetTransactionHistory = (0, import_react5.useCallback)(async (limit) => {
|
|
6455
|
+
const sdk = socialRef.current;
|
|
6456
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
6457
|
+
return sdk.getTransactionHistory(limit);
|
|
6458
|
+
}, []);
|
|
6058
6459
|
const socialSignTypedData = (0, import_react5.useCallback)(async (req) => {
|
|
6059
6460
|
const sdk = socialRef.current;
|
|
6060
6461
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
@@ -6132,6 +6533,7 @@ function DecaneKit({ config, children }) {
|
|
|
6132
6533
|
socialAuth,
|
|
6133
6534
|
signInWithPasskey,
|
|
6134
6535
|
connectWithGoogle,
|
|
6536
|
+
connectWithKingsChat,
|
|
6135
6537
|
connectWithEmail,
|
|
6136
6538
|
verifyEmailCode: verifyEmailCode2,
|
|
6137
6539
|
connectWithToken,
|
|
@@ -6146,6 +6548,8 @@ function DecaneKit({ config, children }) {
|
|
|
6146
6548
|
socialGetEthereumProvider,
|
|
6147
6549
|
socialSignAuthorization,
|
|
6148
6550
|
socialSignTronTransaction,
|
|
6551
|
+
socialRecordTransaction,
|
|
6552
|
+
socialGetTransactionHistory,
|
|
6149
6553
|
socialGetAccessToken,
|
|
6150
6554
|
socialSignSolanaTransaction,
|
|
6151
6555
|
socialSignTypedData,
|
|
@@ -6172,6 +6576,7 @@ function DecaneKit({ config, children }) {
|
|
|
6172
6576
|
mode,
|
|
6173
6577
|
socialAuthMethods: config?.social?.authMethods ?? ["google", "email"],
|
|
6174
6578
|
onGoogleSignIn: connectWithGoogle,
|
|
6579
|
+
onKingsChatSignIn: connectWithKingsChat,
|
|
6175
6580
|
onEmailStart: connectWithEmail,
|
|
6176
6581
|
onEmailVerify: verifyEmailCode2,
|
|
6177
6582
|
canUsePasskey: socialAuth.canUsePasskey,
|
|
@@ -6193,6 +6598,7 @@ function DecaneKit({ config, children }) {
|
|
|
6193
6598
|
customAuthLabel: customAuthConfig?.label,
|
|
6194
6599
|
onCustomAuthSignIn: customAuthConfig ? connectWithCustomAuth : void 0,
|
|
6195
6600
|
onGoogleSignIn: connectWithGoogle,
|
|
6601
|
+
onKingsChatSignIn: connectWithKingsChat,
|
|
6196
6602
|
onEmailStart: connectWithEmail,
|
|
6197
6603
|
onEmailVerify: verifyEmailCode2,
|
|
6198
6604
|
authMethods: config?.social?.authMethods ?? ["google", "email"],
|
|
@@ -6367,6 +6773,8 @@ function useSocialWallet() {
|
|
|
6367
6773
|
socialSendTransaction,
|
|
6368
6774
|
socialSignSolanaTransaction,
|
|
6369
6775
|
socialSignTronTransaction,
|
|
6776
|
+
socialRecordTransaction,
|
|
6777
|
+
socialGetTransactionHistory,
|
|
6370
6778
|
socialSignTypedData,
|
|
6371
6779
|
socialGetBalance,
|
|
6372
6780
|
socialGetBalances,
|
|
@@ -6413,6 +6821,14 @@ function useSocialWallet() {
|
|
|
6413
6821
|
(rawDataHex) => run(() => socialSignTronTransaction(rawDataHex)),
|
|
6414
6822
|
[socialSignTronTransaction]
|
|
6415
6823
|
);
|
|
6824
|
+
const recordTransaction = (0, import_react6.useCallback)(
|
|
6825
|
+
(tx) => run(() => socialRecordTransaction(tx)),
|
|
6826
|
+
[socialRecordTransaction]
|
|
6827
|
+
);
|
|
6828
|
+
const getTransactionHistory = (0, import_react6.useCallback)(
|
|
6829
|
+
(limit) => socialGetTransactionHistory(limit),
|
|
6830
|
+
[socialGetTransactionHistory]
|
|
6831
|
+
);
|
|
6416
6832
|
const signTypedData = (0, import_react6.useCallback)(
|
|
6417
6833
|
(req) => run(() => socialSignTypedData(req)),
|
|
6418
6834
|
[socialSignTypedData]
|
|
@@ -6495,6 +6911,8 @@ function useSocialWallet() {
|
|
|
6495
6911
|
sendTransaction,
|
|
6496
6912
|
signSolanaTransaction: signSolanaTransaction2,
|
|
6497
6913
|
signTronTransaction,
|
|
6914
|
+
recordTransaction,
|
|
6915
|
+
getTransactionHistory,
|
|
6498
6916
|
signTypedData,
|
|
6499
6917
|
// Balances (native token; read-only, works while locked)
|
|
6500
6918
|
getBalance,
|
|
@@ -6825,6 +7243,7 @@ function useSignTypedData() {
|
|
|
6825
7243
|
SessionExpiredError,
|
|
6826
7244
|
ShareCorruptedError,
|
|
6827
7245
|
SocialWalletModal,
|
|
7246
|
+
StaleDeviceShareError,
|
|
6828
7247
|
UnlockRequiredError,
|
|
6829
7248
|
UserCancelledError,
|
|
6830
7249
|
WalletSelector,
|
|
@@ -6833,6 +7252,7 @@ function useSignTypedData() {
|
|
|
6833
7252
|
createDecane,
|
|
6834
7253
|
createDecaneConnect,
|
|
6835
7254
|
createEthereumProvider,
|
|
7255
|
+
loginWithKingsChatPopup,
|
|
6836
7256
|
startEmailAuth,
|
|
6837
7257
|
useChainSwitch,
|
|
6838
7258
|
useDecane,
|