decane-connect-kit 2.2.1 → 2.2.3
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 +265 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +261 -61
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -183,6 +183,9 @@ __export(index_exports, {
|
|
|
183
183
|
DecaneError: () => DecaneError,
|
|
184
184
|
DecaneErrorCode: () => DecaneErrorCode,
|
|
185
185
|
DecaneKit: () => DecaneKit,
|
|
186
|
+
DecaneLogo: () => DecaneLogo,
|
|
187
|
+
DecaneMark: () => DecaneMark,
|
|
188
|
+
DecaneWordmark: () => DecaneWordmark,
|
|
186
189
|
ExportNotAuthorizedError: () => ExportNotAuthorizedError,
|
|
187
190
|
InvalidApiKeyError: () => InvalidApiKeyError,
|
|
188
191
|
InvalidPinError: () => InvalidPinError,
|
|
@@ -211,6 +214,7 @@ __export(index_exports, {
|
|
|
211
214
|
useSignMessage: () => useSignMessage,
|
|
212
215
|
useSignTypedData: () => useSignTypedData,
|
|
213
216
|
useSocialAuth: () => useSocialAuth,
|
|
217
|
+
useSocialBalance: () => useSocialBalance,
|
|
214
218
|
useSocialWallet: () => useSocialWallet,
|
|
215
219
|
useWalletSelector: () => useWalletSelector,
|
|
216
220
|
verifyEmailCode: () => verifyEmailCode
|
|
@@ -1983,7 +1987,11 @@ var EventEmitter = class {
|
|
|
1983
1987
|
init_errors();
|
|
1984
1988
|
var ERROR_MAP = {
|
|
1985
1989
|
INVALID_API_KEY: InvalidApiKeyError,
|
|
1986
|
-
ORIGIN_NOT_ALLOWED: OriginNotAllowedError
|
|
1990
|
+
ORIGIN_NOT_ALLOWED: OriginNotAllowedError,
|
|
1991
|
+
// The backend's authMiddleware code for an expired/revoked JWT. Surfacing it
|
|
1992
|
+
// as ReconnectRequiredError routes callers to the sign-in UI instead of a
|
|
1993
|
+
// generic failure message.
|
|
1994
|
+
UNAUTHORIZED: ReconnectRequiredError
|
|
1987
1995
|
};
|
|
1988
1996
|
var ApiClient = class {
|
|
1989
1997
|
constructor(baseUrl, apiKey, appId) {
|
|
@@ -2269,11 +2277,22 @@ var TeeClient = class {
|
|
|
2269
2277
|
this.attested = false;
|
|
2270
2278
|
/** Mirrors what the signer confirmed for this session, not what we asked for. */
|
|
2271
2279
|
this.assertionPerSignature = false;
|
|
2280
|
+
/** The signer's authoritative remaining lifetime (seconds), null until a session opens. */
|
|
2281
|
+
this.sessionExpiresInSec = null;
|
|
2272
2282
|
}
|
|
2273
2283
|
/** Whether this session actually got per-signature assertions. */
|
|
2274
2284
|
requiresAssertionPerSignature() {
|
|
2275
2285
|
return this.assertionPerSignature;
|
|
2276
2286
|
}
|
|
2287
|
+
/**
|
|
2288
|
+
* The lifetime the signer granted this session, in seconds — which can be
|
|
2289
|
+
* shorter than the client's configured duration when the JWT expires first.
|
|
2290
|
+
* Null if the signer didn't report one (older build). Callers clamp their own
|
|
2291
|
+
* countdown to this so it never promises time the handle doesn't have.
|
|
2292
|
+
*/
|
|
2293
|
+
sessionExpiresIn() {
|
|
2294
|
+
return this.sessionExpiresInSec;
|
|
2295
|
+
}
|
|
2277
2296
|
async ensureAttested() {
|
|
2278
2297
|
if (this.attested) return;
|
|
2279
2298
|
const nonce = crypto.getRandomValues(new Uint8Array(16));
|
|
@@ -2302,6 +2321,7 @@ var TeeClient = class {
|
|
|
2302
2321
|
const body = await res.json();
|
|
2303
2322
|
this.handle = body.handle;
|
|
2304
2323
|
this.assertionPerSignature = body.requireAssertionPerSignature === true;
|
|
2324
|
+
this.sessionExpiresInSec = typeof body.expiresIn === "number" ? body.expiresIn : null;
|
|
2305
2325
|
return body.addresses ?? null;
|
|
2306
2326
|
}
|
|
2307
2327
|
/**
|
|
@@ -2344,6 +2364,7 @@ var TeeClient = class {
|
|
|
2344
2364
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2345
2365
|
body: JSON.stringify({ rpId: window.location.hostname })
|
|
2346
2366
|
});
|
|
2367
|
+
if (res.status === 401) throw new ReconnectRequiredError();
|
|
2347
2368
|
if (!res.ok) throw new ExportNotAuthorizedError();
|
|
2348
2369
|
const { challengeId, options } = await res.json();
|
|
2349
2370
|
let assertion;
|
|
@@ -2395,8 +2416,9 @@ var TeeClient = class {
|
|
|
2395
2416
|
/**
|
|
2396
2417
|
* `jwt` is only needed when this session requires per-signature assertions —
|
|
2397
2418
|
* it authenticates the challenge request. Passed per call rather than cached
|
|
2398
|
-
* on the instance deliberately:
|
|
2399
|
-
* TEE session TTL
|
|
2419
|
+
* on the instance deliberately: JWT lifetime is configured independently of
|
|
2420
|
+
* the TEE session TTL (they are aligned at 30min by default, but an operator
|
|
2421
|
+
* can shorten JWT_EXPIRY_SECONDS), so a stored copy could go stale mid-session.
|
|
2400
2422
|
*/
|
|
2401
2423
|
async sign(req, jwt) {
|
|
2402
2424
|
if (!this.handle) throw new Error("no session");
|
|
@@ -2486,12 +2508,14 @@ var SessionManager = class {
|
|
|
2486
2508
|
}
|
|
2487
2509
|
this.evmAddress = addresses.evm;
|
|
2488
2510
|
this.solanaAddress = addresses.solana;
|
|
2489
|
-
|
|
2511
|
+
const serverTtlMs = this.tee.sessionExpiresIn();
|
|
2512
|
+
const effectiveMs = serverTtlMs != null ? Math.min(this.durationMs, serverTtlMs * 1e3) : this.durationMs;
|
|
2513
|
+
this.expiresAt = Date.now() + effectiveMs;
|
|
2490
2514
|
if (this.timeoutId) clearTimeout(this.timeoutId);
|
|
2491
2515
|
this.timeoutId = setTimeout(() => {
|
|
2492
2516
|
this.end();
|
|
2493
2517
|
this.events.emit("session-expired");
|
|
2494
|
-
},
|
|
2518
|
+
}, effectiveMs);
|
|
2495
2519
|
this.events.emit("session-started");
|
|
2496
2520
|
return addresses;
|
|
2497
2521
|
}
|
|
@@ -2715,6 +2739,13 @@ async function signEvmTransaction(tee, chain, tx, jwt) {
|
|
|
2715
2739
|
async function signEvmMessage(tee, chain, message, jwt) {
|
|
2716
2740
|
return tee.sign({ chain, kind: "message", payload: message }, jwt);
|
|
2717
2741
|
}
|
|
2742
|
+
async function signEvmTypedData(tee, chain, typedData, jwt) {
|
|
2743
|
+
const payload = JSON.stringify(
|
|
2744
|
+
typedData,
|
|
2745
|
+
(_k, v) => typeof v === "bigint" ? v.toString() : v
|
|
2746
|
+
);
|
|
2747
|
+
return tee.sign({ chain, kind: "typedData", payload }, jwt);
|
|
2748
|
+
}
|
|
2718
2749
|
|
|
2719
2750
|
// src/social/signers/solana.ts
|
|
2720
2751
|
var import_web3 = require("@solana/web3.js");
|
|
@@ -2953,10 +2984,7 @@ async function buildPortableBackup(deviceShare, recoveryShare, password, address
|
|
|
2953
2984
|
};
|
|
2954
2985
|
}
|
|
2955
2986
|
|
|
2956
|
-
// src/social/
|
|
2957
|
-
var DEFAULT_API_BASE = "https://backend.decane.app";
|
|
2958
|
-
var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
|
|
2959
|
-
var DEFAULT_SESSION_MINUTES = 30;
|
|
2987
|
+
// src/social/balance.ts
|
|
2960
2988
|
var DEFAULT_RPCS = {
|
|
2961
2989
|
"evm:1": "https://ethereum.publicnode.com",
|
|
2962
2990
|
"evm:137": "https://polygon.publicnode.com",
|
|
@@ -2968,6 +2996,50 @@ var DEFAULT_RPCS = {
|
|
|
2968
2996
|
"evm:84532": "https://base-sepolia.publicnode.com",
|
|
2969
2997
|
"evm:31337": "http://localhost:8545"
|
|
2970
2998
|
};
|
|
2999
|
+
var EVM_SYMBOLS = {
|
|
3000
|
+
"evm:137": "MATIC",
|
|
3001
|
+
"evm:56": "BNB"
|
|
3002
|
+
};
|
|
3003
|
+
function solanaEndpoint(chain, rpcUrls) {
|
|
3004
|
+
if (rpcUrls?.[chain]) return rpcUrls[chain];
|
|
3005
|
+
const cluster = chain.slice("solana:".length);
|
|
3006
|
+
return cluster === "devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com";
|
|
3007
|
+
}
|
|
3008
|
+
async function fetchBalance(opts) {
|
|
3009
|
+
const { kind, address, chain, rpcUrls } = opts;
|
|
3010
|
+
if (kind === "evm") {
|
|
3011
|
+
const rpcUrl = rpcUrls?.[chain] ?? DEFAULT_RPCS[chain];
|
|
3012
|
+
if (!rpcUrl) {
|
|
3013
|
+
throw new Error(
|
|
3014
|
+
`No RPC URL for ${chain}. Pass rpcUrls: { '${chain}': 'https://...' } in social config.`
|
|
3015
|
+
);
|
|
3016
|
+
}
|
|
3017
|
+
const { JsonRpcProvider, formatEther } = await import("ethers");
|
|
3018
|
+
const wei = await new JsonRpcProvider(rpcUrl).getBalance(address);
|
|
3019
|
+
return { raw: wei, formatted: formatEther(wei), symbol: EVM_SYMBOLS[chain] ?? "ETH", decimals: 18 };
|
|
3020
|
+
}
|
|
3021
|
+
const { Connection, PublicKey, LAMPORTS_PER_SOL } = await import("@solana/web3.js");
|
|
3022
|
+
const lamports = await new Connection(solanaEndpoint(chain, rpcUrls)).getBalance(
|
|
3023
|
+
new PublicKey(address)
|
|
3024
|
+
);
|
|
3025
|
+
return {
|
|
3026
|
+
raw: BigInt(lamports),
|
|
3027
|
+
formatted: String(lamports / LAMPORTS_PER_SOL),
|
|
3028
|
+
symbol: "SOL",
|
|
3029
|
+
decimals: 9
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
function formatBalanceDisplay(value) {
|
|
3033
|
+
if (value == null) return "\u2014";
|
|
3034
|
+
const n = Number(value);
|
|
3035
|
+
if (!Number.isFinite(n)) return value;
|
|
3036
|
+
return n === 0 ? "0" : n < 1e-4 ? "<0.0001" : n.toFixed(4).replace(/\.?0+$/, "");
|
|
3037
|
+
}
|
|
3038
|
+
|
|
3039
|
+
// src/social/client.ts
|
|
3040
|
+
var DEFAULT_API_BASE = "https://backend.decane.app";
|
|
3041
|
+
var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
|
|
3042
|
+
var DEFAULT_SESSION_MINUTES = 30;
|
|
2971
3043
|
function makePersistKey(apiKey) {
|
|
2972
3044
|
return `decane:social:${apiKey.slice(0, 20)}`;
|
|
2973
3045
|
}
|
|
@@ -3465,6 +3537,23 @@ async function createDecaneConnect(config) {
|
|
|
3465
3537
|
const txResponse = await provider.broadcastTransaction(signedTx);
|
|
3466
3538
|
return txResponse.hash;
|
|
3467
3539
|
},
|
|
3540
|
+
async signTypedData(req) {
|
|
3541
|
+
const tee = session.requireActive();
|
|
3542
|
+
if (!req.chain.startsWith("evm:")) {
|
|
3543
|
+
throw new CallSequenceError("signTypedData is EVM-only (EIP-712).");
|
|
3544
|
+
}
|
|
3545
|
+
return signEvmTypedData(
|
|
3546
|
+
tee,
|
|
3547
|
+
req.chain,
|
|
3548
|
+
{
|
|
3549
|
+
domain: req.domain,
|
|
3550
|
+
types: req.types,
|
|
3551
|
+
message: req.message,
|
|
3552
|
+
primaryType: req.primaryType
|
|
3553
|
+
},
|
|
3554
|
+
auth?.jwt
|
|
3555
|
+
);
|
|
3556
|
+
},
|
|
3468
3557
|
async signSolanaTransaction(serializedTx) {
|
|
3469
3558
|
const tee = session.requireActive();
|
|
3470
3559
|
let tx;
|
|
@@ -3490,6 +3579,42 @@ async function createDecaneConnect(config) {
|
|
|
3490
3579
|
getAddresses() {
|
|
3491
3580
|
return auth?.addresses ?? persisted?.addresses ?? null;
|
|
3492
3581
|
},
|
|
3582
|
+
// Native-token balance. Read-only public chain data, so it works whenever an
|
|
3583
|
+
// address is known — including while the wallet is locked (no TEE session
|
|
3584
|
+
// needed). `chain` defaults to the first configured EVM chain, else the
|
|
3585
|
+
// first Solana chain.
|
|
3586
|
+
async getBalance(chain) {
|
|
3587
|
+
const addresses = auth?.addresses ?? persisted?.addresses;
|
|
3588
|
+
if (!addresses) throw new CallSequenceError("Not connected \u2014 no wallet address known");
|
|
3589
|
+
const resolvedChain = chain ?? config.chains.find((c) => c.startsWith("evm:")) ?? config.chains.find((c) => c.startsWith("solana:"));
|
|
3590
|
+
if (!resolvedChain) throw new CallSequenceError("No chain configured");
|
|
3591
|
+
const kind = resolvedChain.startsWith("solana:") ? "solana" : "evm";
|
|
3592
|
+
const address = kind === "evm" ? addresses.evm : addresses.solana;
|
|
3593
|
+
if (!address) throw new CallSequenceError(`This wallet has no ${kind} address`);
|
|
3594
|
+
return fetchBalance({ kind, address, chain: resolvedChain, rpcUrls: config.rpcUrls });
|
|
3595
|
+
},
|
|
3596
|
+
// Balances across every configured chain the wallet has an address for.
|
|
3597
|
+
// Per-chain failures resolve to null rather than rejecting the whole call,
|
|
3598
|
+
// so one dead RPC doesn't blank the entire list.
|
|
3599
|
+
async getBalances() {
|
|
3600
|
+
const addresses = auth?.addresses ?? persisted?.addresses;
|
|
3601
|
+
if (!addresses) throw new CallSequenceError("Not connected \u2014 no wallet address known");
|
|
3602
|
+
const targets = config.chains.filter((c) => {
|
|
3603
|
+
const kind = c.startsWith("solana:") ? "solana" : "evm";
|
|
3604
|
+
return kind === "evm" ? !!addresses.evm : !!addresses.solana;
|
|
3605
|
+
});
|
|
3606
|
+
return Promise.all(
|
|
3607
|
+
targets.map(async (chain) => {
|
|
3608
|
+
const kind = chain.startsWith("solana:") ? "solana" : "evm";
|
|
3609
|
+
const address = kind === "evm" ? addresses.evm : addresses.solana;
|
|
3610
|
+
try {
|
|
3611
|
+
return { chain, balance: await fetchBalance({ kind, address, chain, rpcUrls: config.rpcUrls }) };
|
|
3612
|
+
} catch {
|
|
3613
|
+
return { chain, balance: null };
|
|
3614
|
+
}
|
|
3615
|
+
})
|
|
3616
|
+
);
|
|
3617
|
+
},
|
|
3493
3618
|
async rotateShares(opts) {
|
|
3494
3619
|
if (!auth) throw new CallSequenceError("Not connected \u2014 call connect() first");
|
|
3495
3620
|
const tee = session.requireActive();
|
|
@@ -3736,6 +3861,31 @@ var CSS_VARS = {
|
|
|
3736
3861
|
|
|
3737
3862
|
// src/ui/icons.tsx
|
|
3738
3863
|
var import_react = __toESM(require("react"), 1);
|
|
3864
|
+
var DECAGON_OUTER = "12,2 17.88,3.91 21.51,8.91 21.51,15.09 17.88,20.09 12,22 6.12,20.09 2.49,15.09 2.49,8.91 6.12,3.91";
|
|
3865
|
+
var DECAGON_INNER = "12,7.4 14.7,8.28 16.37,10.58 16.37,13.42 14.7,15.72 12,16.6 9.3,15.72 7.63,13.42 7.63,10.58 9.3,8.28";
|
|
3866
|
+
function DecaneMark({ size = 24, muted = false }) {
|
|
3867
|
+
const color = muted ? "var(--dc-text-muted)" : "var(--dc-accent)";
|
|
3868
|
+
return /* @__PURE__ */ import_react.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, style: { flexShrink: 0, display: "block" } }, /* @__PURE__ */ import_react.default.createElement("polygon", { points: DECAGON_OUTER, fill: color, fillOpacity: muted ? 0.08 : 0.1, stroke: color, strokeWidth: "1.4", strokeLinejoin: "round" }), /* @__PURE__ */ import_react.default.createElement("polygon", { points: DECAGON_INNER, fill: color, fillOpacity: muted ? 0.55 : 0.95 }));
|
|
3869
|
+
}
|
|
3870
|
+
function DecaneWordmark({ size = 15, muted = false }) {
|
|
3871
|
+
return /* @__PURE__ */ import_react.default.createElement(
|
|
3872
|
+
"span",
|
|
3873
|
+
{
|
|
3874
|
+
style: {
|
|
3875
|
+
fontFamily: "var(--dc-font-sans, system-ui, sans-serif)",
|
|
3876
|
+
fontWeight: 800,
|
|
3877
|
+
fontSize: size,
|
|
3878
|
+
letterSpacing: "-0.03em",
|
|
3879
|
+
color: muted ? "var(--dc-text-muted)" : "var(--dc-text)",
|
|
3880
|
+
lineHeight: 1
|
|
3881
|
+
}
|
|
3882
|
+
},
|
|
3883
|
+
"decane"
|
|
3884
|
+
);
|
|
3885
|
+
}
|
|
3886
|
+
function DecaneLogo({ size = 20, muted = false }) {
|
|
3887
|
+
return /* @__PURE__ */ import_react.default.createElement("span", { style: { display: "inline-flex", alignItems: "center", gap: size * 0.34 } }, /* @__PURE__ */ import_react.default.createElement(DecaneMark, { size, muted }), /* @__PURE__ */ import_react.default.createElement(DecaneWordmark, { size: size * 0.78, muted }));
|
|
3888
|
+
}
|
|
3739
3889
|
function WalletIcon({ src, name, size = 36 }) {
|
|
3740
3890
|
if (src) {
|
|
3741
3891
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
@@ -4689,40 +4839,17 @@ function useBalance(kind, address, chain, rpcUrls) {
|
|
|
4689
4839
|
if (!address || !chain) return;
|
|
4690
4840
|
let cancelled = false;
|
|
4691
4841
|
setState((s) => ({ ...s, loading: true }));
|
|
4692
|
-
(
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
if (!cancelled) setState({ loading: false, value: null, symbol: "ETH" });
|
|
4698
|
-
return;
|
|
4699
|
-
}
|
|
4700
|
-
const { JsonRpcProvider, formatEther } = await import("ethers");
|
|
4701
|
-
const wei = await new JsonRpcProvider(rpcUrl).getBalance(address);
|
|
4702
|
-
if (!cancelled) setState({ loading: false, value: formatEther(wei), symbol: "ETH" });
|
|
4703
|
-
} else {
|
|
4704
|
-
const cluster = chain.slice("solana:".length);
|
|
4705
|
-
const endpoint = rpcUrls?.[chain] ?? (cluster === "devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com");
|
|
4706
|
-
const { Connection, PublicKey, LAMPORTS_PER_SOL } = await import("@solana/web3.js");
|
|
4707
|
-
const lamports = await new Connection(endpoint).getBalance(new PublicKey(address));
|
|
4708
|
-
if (!cancelled) setState({ loading: false, value: String(lamports / LAMPORTS_PER_SOL), symbol: "SOL" });
|
|
4709
|
-
}
|
|
4710
|
-
} catch {
|
|
4711
|
-
if (!cancelled) setState({ loading: false, value: null, symbol: kind === "evm" ? "ETH" : "SOL" });
|
|
4712
|
-
}
|
|
4713
|
-
})();
|
|
4842
|
+
fetchBalance({ kind, address, chain, rpcUrls }).then((b) => {
|
|
4843
|
+
if (!cancelled) setState({ loading: false, value: b.formatted, symbol: b.symbol });
|
|
4844
|
+
}).catch(() => {
|
|
4845
|
+
if (!cancelled) setState({ loading: false, value: null, symbol: kind === "evm" ? "ETH" : "SOL" });
|
|
4846
|
+
});
|
|
4714
4847
|
return () => {
|
|
4715
4848
|
cancelled = true;
|
|
4716
4849
|
};
|
|
4717
4850
|
}, [kind, address, chain, rpcUrls]);
|
|
4718
4851
|
return state;
|
|
4719
4852
|
}
|
|
4720
|
-
function formatBalance(value) {
|
|
4721
|
-
if (value == null) return "\u2014";
|
|
4722
|
-
const n = Number(value);
|
|
4723
|
-
if (!Number.isFinite(n)) return value;
|
|
4724
|
-
return n === 0 ? "0" : n < 1e-4 ? "<0.0001" : n.toFixed(4).replace(/\.?0+$/, "");
|
|
4725
|
-
}
|
|
4726
4853
|
function AddressRow({
|
|
4727
4854
|
label,
|
|
4728
4855
|
address,
|
|
@@ -4738,7 +4865,7 @@ function AddressRow({
|
|
|
4738
4865
|
borderRadius: 10,
|
|
4739
4866
|
padding: "10px 14px",
|
|
4740
4867
|
marginBottom: 8
|
|
4741
|
-
} }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 5 } }, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "0.06em", textTransform: "uppercase" } }, label), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 11, fontFamily: "monospace", color: "var(--dc-text)" } }, balance.loading ? "\u2026" : `${
|
|
4868
|
+
} }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 5 } }, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "0.06em", textTransform: "uppercase" } }, label), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 11, fontFamily: "monospace", color: "var(--dc-text)" } }, balance.loading ? "\u2026" : `${formatBalanceDisplay(balance.value)} ${balance.symbol}`)), /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 } }, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 13, fontFamily: "monospace", color: "var(--dc-text)", letterSpacing: "0.02em" } }, short), /* @__PURE__ */ import_react3.default.createElement(CopyButton, { value: address })));
|
|
4742
4869
|
}
|
|
4743
4870
|
function SignInView({
|
|
4744
4871
|
onGoogleSignIn,
|
|
@@ -5115,34 +5242,17 @@ function SocialWalletModal({
|
|
|
5115
5242
|
top: 0,
|
|
5116
5243
|
zIndex: 1,
|
|
5117
5244
|
background: "linear-gradient(90deg, transparent, var(--dc-accent) 30%, var(--dc-accent) 70%, transparent)"
|
|
5118
|
-
} }), /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "18px 20px 16px", display: "flex", alignItems: "center", gap:
|
|
5119
|
-
width:
|
|
5120
|
-
height:
|
|
5121
|
-
borderRadius:
|
|
5245
|
+
} }), /* @__PURE__ */ import_react3.default.createElement("div", { style: { padding: "18px 20px 16px", display: "flex", alignItems: "center", gap: 11 } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: {
|
|
5246
|
+
width: 38,
|
|
5247
|
+
height: 38,
|
|
5248
|
+
borderRadius: 11,
|
|
5122
5249
|
background: "var(--dc-surface)",
|
|
5123
5250
|
border: "1px solid var(--dc-border)",
|
|
5124
5251
|
display: "flex",
|
|
5125
5252
|
alignItems: "center",
|
|
5126
5253
|
justifyContent: "center",
|
|
5127
5254
|
flexShrink: 0
|
|
5128
|
-
} }, /* @__PURE__ */ import_react3.default.createElement("
|
|
5129
|
-
"path",
|
|
5130
|
-
{
|
|
5131
|
-
d: "M8 1L1.5 3.5V8.5C1.5 12.09 4.35 15.4 8 16.5C11.65 15.4 14.5 12.09 14.5 8.5V3.5L8 1Z",
|
|
5132
|
-
stroke: "var(--dc-accent)",
|
|
5133
|
-
strokeWidth: "1.4",
|
|
5134
|
-
strokeLinejoin: "round"
|
|
5135
|
-
}
|
|
5136
|
-
), /* @__PURE__ */ import_react3.default.createElement(
|
|
5137
|
-
"path",
|
|
5138
|
-
{
|
|
5139
|
-
d: "M5.5 9L7 10.5L10.5 7",
|
|
5140
|
-
stroke: "var(--dc-accent)",
|
|
5141
|
-
strokeWidth: "1.4",
|
|
5142
|
-
strokeLinecap: "round",
|
|
5143
|
-
strokeLinejoin: "round"
|
|
5144
|
-
}
|
|
5145
|
-
))), /* @__PURE__ */ import_react3.default.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 15, fontWeight: 800, color: "var(--dc-text)", letterSpacing: "-0.02em" } }, "Social Wallet"), /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 11, color: "var(--dc-text-muted)", marginTop: 1 } }, "Decane non-custodial \xB7 key split three ways")), /* @__PURE__ */ import_react3.default.createElement(
|
|
5255
|
+
} }, /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 22 })), /* @__PURE__ */ import_react3.default.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 6 } }, /* @__PURE__ */ import_react3.default.createElement(DecaneWordmark, { size: 15 }), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 13, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "-0.01em" } }, "wallet")), /* @__PURE__ */ import_react3.default.createElement("div", { style: { fontSize: 11, color: "var(--dc-text-muted)", marginTop: 2 } }, "Non-custodial \xB7 key split three ways")), /* @__PURE__ */ import_react3.default.createElement(
|
|
5146
5256
|
"button",
|
|
5147
5257
|
{
|
|
5148
5258
|
onClick: onClose,
|
|
@@ -5245,7 +5355,14 @@ function SocialWalletModal({
|
|
|
5245
5355
|
}
|
|
5246
5356
|
},
|
|
5247
5357
|
disconnecting ? "Signing out\u2026" : "Sign out"
|
|
5248
|
-
)))
|
|
5358
|
+
))), /* @__PURE__ */ import_react3.default.createElement("div", { style: {
|
|
5359
|
+
padding: "11px 16px",
|
|
5360
|
+
borderTop: "1px solid var(--dc-border)",
|
|
5361
|
+
display: "flex",
|
|
5362
|
+
alignItems: "center",
|
|
5363
|
+
justifyContent: "center",
|
|
5364
|
+
gap: 6
|
|
5365
|
+
} }, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontSize: 10.5, color: "var(--dc-text-muted)", letterSpacing: "0.02em" } }, "Secured by"), /* @__PURE__ */ import_react3.default.createElement(DecaneMark, { size: 13, muted: true }), /* @__PURE__ */ import_react3.default.createElement(DecaneWordmark, { size: 11, muted: true })))
|
|
5249
5366
|
);
|
|
5250
5367
|
return (0, import_react_dom2.createPortal)(modal, document.body);
|
|
5251
5368
|
}
|
|
@@ -5431,6 +5548,21 @@ function DecaneKit({ config, children }) {
|
|
|
5431
5548
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
5432
5549
|
return sdk.signSolanaTransaction(tx);
|
|
5433
5550
|
}, []);
|
|
5551
|
+
const socialSignTypedData = (0, import_react4.useCallback)(async (req) => {
|
|
5552
|
+
const sdk = socialRef.current;
|
|
5553
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
5554
|
+
return sdk.signTypedData({ ...req, chain: req.chain });
|
|
5555
|
+
}, []);
|
|
5556
|
+
const socialGetBalance = (0, import_react4.useCallback)(async (chain) => {
|
|
5557
|
+
const sdk = socialRef.current;
|
|
5558
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
5559
|
+
return sdk.getBalance(chain);
|
|
5560
|
+
}, []);
|
|
5561
|
+
const socialGetBalances = (0, import_react4.useCallback)(async () => {
|
|
5562
|
+
const sdk = socialRef.current;
|
|
5563
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
5564
|
+
return sdk.getBalances();
|
|
5565
|
+
}, []);
|
|
5434
5566
|
const socialRotateShares = (0, import_react4.useCallback)(async (opts) => {
|
|
5435
5567
|
const sdk = socialRef.current;
|
|
5436
5568
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
@@ -5486,7 +5618,10 @@ function DecaneKit({ config, children }) {
|
|
|
5486
5618
|
socialDisconnect,
|
|
5487
5619
|
socialSignMessage,
|
|
5488
5620
|
socialSendTransaction,
|
|
5621
|
+
socialGetBalance,
|
|
5622
|
+
socialGetBalances,
|
|
5489
5623
|
socialSignSolanaTransaction,
|
|
5624
|
+
socialSignTypedData,
|
|
5490
5625
|
socialRotateShares,
|
|
5491
5626
|
socialExportPortableBackup,
|
|
5492
5627
|
socialHasRecoveryShare,
|
|
@@ -5684,6 +5819,9 @@ function useSocialWallet() {
|
|
|
5684
5819
|
socialSignMessage,
|
|
5685
5820
|
socialSendTransaction,
|
|
5686
5821
|
socialSignSolanaTransaction,
|
|
5822
|
+
socialSignTypedData,
|
|
5823
|
+
socialGetBalance,
|
|
5824
|
+
socialGetBalances,
|
|
5687
5825
|
socialRotateShares,
|
|
5688
5826
|
socialExportPortableBackup,
|
|
5689
5827
|
socialHasRecoveryShare,
|
|
@@ -5720,6 +5858,18 @@ function useSocialWallet() {
|
|
|
5720
5858
|
(tx) => run(() => socialSignSolanaTransaction(tx)),
|
|
5721
5859
|
[socialSignSolanaTransaction]
|
|
5722
5860
|
);
|
|
5861
|
+
const signTypedData = (0, import_react5.useCallback)(
|
|
5862
|
+
(req) => run(() => socialSignTypedData(req)),
|
|
5863
|
+
[socialSignTypedData]
|
|
5864
|
+
);
|
|
5865
|
+
const getBalance = (0, import_react5.useCallback)(
|
|
5866
|
+
(chain) => run(() => socialGetBalance(chain)),
|
|
5867
|
+
[socialGetBalance]
|
|
5868
|
+
);
|
|
5869
|
+
const getBalances = (0, import_react5.useCallback)(
|
|
5870
|
+
() => run(() => socialGetBalances()),
|
|
5871
|
+
[socialGetBalances]
|
|
5872
|
+
);
|
|
5723
5873
|
const unlock = (0, import_react5.useCallback)(async () => {
|
|
5724
5874
|
setError(null);
|
|
5725
5875
|
try {
|
|
@@ -5781,6 +5931,10 @@ function useSocialWallet() {
|
|
|
5781
5931
|
signMessage,
|
|
5782
5932
|
sendTransaction,
|
|
5783
5933
|
signSolanaTransaction: signSolanaTransaction2,
|
|
5934
|
+
signTypedData,
|
|
5935
|
+
// Balances (native token; read-only, works while locked)
|
|
5936
|
+
getBalance,
|
|
5937
|
+
getBalances,
|
|
5784
5938
|
// Recovery (2-of-3 Shamir share set)
|
|
5785
5939
|
rotateShares,
|
|
5786
5940
|
exportPortableBackup,
|
|
@@ -5792,6 +5946,52 @@ function useSocialWallet() {
|
|
|
5792
5946
|
clearError: () => setError(null)
|
|
5793
5947
|
};
|
|
5794
5948
|
}
|
|
5949
|
+
function useSocialBalance(chain) {
|
|
5950
|
+
const { socialAuth, socialGetBalance } = useDecaneContext();
|
|
5951
|
+
const [balance, setBalance] = (0, import_react5.useState)(null);
|
|
5952
|
+
const [loading, setLoading] = (0, import_react5.useState)(false);
|
|
5953
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
5954
|
+
const addrKey = `${socialAuth.addresses?.evm ?? ""}|${socialAuth.addresses?.solana ?? ""}`;
|
|
5955
|
+
const refetch = (0, import_react5.useCallback)(async () => {
|
|
5956
|
+
if (!socialAuth.addresses) {
|
|
5957
|
+
setBalance(null);
|
|
5958
|
+
return;
|
|
5959
|
+
}
|
|
5960
|
+
setLoading(true);
|
|
5961
|
+
setError(null);
|
|
5962
|
+
try {
|
|
5963
|
+
setBalance(await socialGetBalance(chain));
|
|
5964
|
+
} catch (e) {
|
|
5965
|
+
setError(e.message);
|
|
5966
|
+
setBalance(null);
|
|
5967
|
+
} finally {
|
|
5968
|
+
setLoading(false);
|
|
5969
|
+
}
|
|
5970
|
+
}, [socialGetBalance, chain, socialAuth.addresses]);
|
|
5971
|
+
(0, import_react5.useEffect)(() => {
|
|
5972
|
+
let cancelled = false;
|
|
5973
|
+
if (!socialAuth.addresses) {
|
|
5974
|
+
setBalance(null);
|
|
5975
|
+
return;
|
|
5976
|
+
}
|
|
5977
|
+
setLoading(true);
|
|
5978
|
+
setError(null);
|
|
5979
|
+
socialGetBalance(chain).then((b) => {
|
|
5980
|
+
if (!cancelled) setBalance(b);
|
|
5981
|
+
}).catch((e) => {
|
|
5982
|
+
if (!cancelled) {
|
|
5983
|
+
setError(e.message);
|
|
5984
|
+
setBalance(null);
|
|
5985
|
+
}
|
|
5986
|
+
}).finally(() => {
|
|
5987
|
+
if (!cancelled) setLoading(false);
|
|
5988
|
+
});
|
|
5989
|
+
return () => {
|
|
5990
|
+
cancelled = true;
|
|
5991
|
+
};
|
|
5992
|
+
}, [addrKey, chain]);
|
|
5993
|
+
return { balance, loading, error, refetch };
|
|
5994
|
+
}
|
|
5795
5995
|
function toDecaneError(err) {
|
|
5796
5996
|
if (err instanceof DecaneError) return err;
|
|
5797
5997
|
const msg = err instanceof Error ? err.message : err?.message != null ? String(err.message) : String(err);
|
|
@@ -6025,6 +6225,9 @@ function useSignTypedData() {
|
|
|
6025
6225
|
DecaneError,
|
|
6026
6226
|
DecaneErrorCode,
|
|
6027
6227
|
DecaneKit,
|
|
6228
|
+
DecaneLogo,
|
|
6229
|
+
DecaneMark,
|
|
6230
|
+
DecaneWordmark,
|
|
6028
6231
|
ExportNotAuthorizedError,
|
|
6029
6232
|
InvalidApiKeyError,
|
|
6030
6233
|
InvalidPinError,
|
|
@@ -6053,6 +6256,7 @@ function useSignTypedData() {
|
|
|
6053
6256
|
useSignMessage,
|
|
6054
6257
|
useSignTypedData,
|
|
6055
6258
|
useSocialAuth,
|
|
6259
|
+
useSocialBalance,
|
|
6056
6260
|
useSocialWallet,
|
|
6057
6261
|
useWalletSelector,
|
|
6058
6262
|
verifyEmailCode
|