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.js
CHANGED
|
@@ -1916,7 +1916,11 @@ var EventEmitter = class {
|
|
|
1916
1916
|
init_errors();
|
|
1917
1917
|
var ERROR_MAP = {
|
|
1918
1918
|
INVALID_API_KEY: InvalidApiKeyError,
|
|
1919
|
-
ORIGIN_NOT_ALLOWED: OriginNotAllowedError
|
|
1919
|
+
ORIGIN_NOT_ALLOWED: OriginNotAllowedError,
|
|
1920
|
+
// The backend's authMiddleware code for an expired/revoked JWT. Surfacing it
|
|
1921
|
+
// as ReconnectRequiredError routes callers to the sign-in UI instead of a
|
|
1922
|
+
// generic failure message.
|
|
1923
|
+
UNAUTHORIZED: ReconnectRequiredError
|
|
1920
1924
|
};
|
|
1921
1925
|
var ApiClient = class {
|
|
1922
1926
|
constructor(baseUrl, apiKey, appId) {
|
|
@@ -2202,11 +2206,22 @@ var TeeClient = class {
|
|
|
2202
2206
|
this.attested = false;
|
|
2203
2207
|
/** Mirrors what the signer confirmed for this session, not what we asked for. */
|
|
2204
2208
|
this.assertionPerSignature = false;
|
|
2209
|
+
/** The signer's authoritative remaining lifetime (seconds), null until a session opens. */
|
|
2210
|
+
this.sessionExpiresInSec = null;
|
|
2205
2211
|
}
|
|
2206
2212
|
/** Whether this session actually got per-signature assertions. */
|
|
2207
2213
|
requiresAssertionPerSignature() {
|
|
2208
2214
|
return this.assertionPerSignature;
|
|
2209
2215
|
}
|
|
2216
|
+
/**
|
|
2217
|
+
* The lifetime the signer granted this session, in seconds — which can be
|
|
2218
|
+
* shorter than the client's configured duration when the JWT expires first.
|
|
2219
|
+
* Null if the signer didn't report one (older build). Callers clamp their own
|
|
2220
|
+
* countdown to this so it never promises time the handle doesn't have.
|
|
2221
|
+
*/
|
|
2222
|
+
sessionExpiresIn() {
|
|
2223
|
+
return this.sessionExpiresInSec;
|
|
2224
|
+
}
|
|
2210
2225
|
async ensureAttested() {
|
|
2211
2226
|
if (this.attested) return;
|
|
2212
2227
|
const nonce = crypto.getRandomValues(new Uint8Array(16));
|
|
@@ -2235,6 +2250,7 @@ var TeeClient = class {
|
|
|
2235
2250
|
const body = await res.json();
|
|
2236
2251
|
this.handle = body.handle;
|
|
2237
2252
|
this.assertionPerSignature = body.requireAssertionPerSignature === true;
|
|
2253
|
+
this.sessionExpiresInSec = typeof body.expiresIn === "number" ? body.expiresIn : null;
|
|
2238
2254
|
return body.addresses ?? null;
|
|
2239
2255
|
}
|
|
2240
2256
|
/**
|
|
@@ -2277,6 +2293,7 @@ var TeeClient = class {
|
|
|
2277
2293
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
2278
2294
|
body: JSON.stringify({ rpId: window.location.hostname })
|
|
2279
2295
|
});
|
|
2296
|
+
if (res.status === 401) throw new ReconnectRequiredError();
|
|
2280
2297
|
if (!res.ok) throw new ExportNotAuthorizedError();
|
|
2281
2298
|
const { challengeId, options } = await res.json();
|
|
2282
2299
|
let assertion;
|
|
@@ -2328,8 +2345,9 @@ var TeeClient = class {
|
|
|
2328
2345
|
/**
|
|
2329
2346
|
* `jwt` is only needed when this session requires per-signature assertions —
|
|
2330
2347
|
* it authenticates the challenge request. Passed per call rather than cached
|
|
2331
|
-
* on the instance deliberately:
|
|
2332
|
-
* TEE session TTL
|
|
2348
|
+
* on the instance deliberately: JWT lifetime is configured independently of
|
|
2349
|
+
* the TEE session TTL (they are aligned at 30min by default, but an operator
|
|
2350
|
+
* can shorten JWT_EXPIRY_SECONDS), so a stored copy could go stale mid-session.
|
|
2333
2351
|
*/
|
|
2334
2352
|
async sign(req, jwt) {
|
|
2335
2353
|
if (!this.handle) throw new Error("no session");
|
|
@@ -2419,12 +2437,14 @@ var SessionManager = class {
|
|
|
2419
2437
|
}
|
|
2420
2438
|
this.evmAddress = addresses.evm;
|
|
2421
2439
|
this.solanaAddress = addresses.solana;
|
|
2422
|
-
|
|
2440
|
+
const serverTtlMs = this.tee.sessionExpiresIn();
|
|
2441
|
+
const effectiveMs = serverTtlMs != null ? Math.min(this.durationMs, serverTtlMs * 1e3) : this.durationMs;
|
|
2442
|
+
this.expiresAt = Date.now() + effectiveMs;
|
|
2423
2443
|
if (this.timeoutId) clearTimeout(this.timeoutId);
|
|
2424
2444
|
this.timeoutId = setTimeout(() => {
|
|
2425
2445
|
this.end();
|
|
2426
2446
|
this.events.emit("session-expired");
|
|
2427
|
-
},
|
|
2447
|
+
}, effectiveMs);
|
|
2428
2448
|
this.events.emit("session-started");
|
|
2429
2449
|
return addresses;
|
|
2430
2450
|
}
|
|
@@ -2648,6 +2668,13 @@ async function signEvmTransaction(tee, chain, tx, jwt) {
|
|
|
2648
2668
|
async function signEvmMessage(tee, chain, message, jwt) {
|
|
2649
2669
|
return tee.sign({ chain, kind: "message", payload: message }, jwt);
|
|
2650
2670
|
}
|
|
2671
|
+
async function signEvmTypedData(tee, chain, typedData, jwt) {
|
|
2672
|
+
const payload = JSON.stringify(
|
|
2673
|
+
typedData,
|
|
2674
|
+
(_k, v) => typeof v === "bigint" ? v.toString() : v
|
|
2675
|
+
);
|
|
2676
|
+
return tee.sign({ chain, kind: "typedData", payload }, jwt);
|
|
2677
|
+
}
|
|
2651
2678
|
|
|
2652
2679
|
// src/social/signers/solana.ts
|
|
2653
2680
|
import { VersionedTransaction as VTx } from "@solana/web3.js";
|
|
@@ -2886,10 +2913,7 @@ async function buildPortableBackup(deviceShare, recoveryShare, password, address
|
|
|
2886
2913
|
};
|
|
2887
2914
|
}
|
|
2888
2915
|
|
|
2889
|
-
// src/social/
|
|
2890
|
-
var DEFAULT_API_BASE = "https://backend.decane.app";
|
|
2891
|
-
var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
|
|
2892
|
-
var DEFAULT_SESSION_MINUTES = 30;
|
|
2916
|
+
// src/social/balance.ts
|
|
2893
2917
|
var DEFAULT_RPCS = {
|
|
2894
2918
|
"evm:1": "https://ethereum.publicnode.com",
|
|
2895
2919
|
"evm:137": "https://polygon.publicnode.com",
|
|
@@ -2901,6 +2925,50 @@ var DEFAULT_RPCS = {
|
|
|
2901
2925
|
"evm:84532": "https://base-sepolia.publicnode.com",
|
|
2902
2926
|
"evm:31337": "http://localhost:8545"
|
|
2903
2927
|
};
|
|
2928
|
+
var EVM_SYMBOLS = {
|
|
2929
|
+
"evm:137": "MATIC",
|
|
2930
|
+
"evm:56": "BNB"
|
|
2931
|
+
};
|
|
2932
|
+
function solanaEndpoint(chain, rpcUrls) {
|
|
2933
|
+
if (rpcUrls?.[chain]) return rpcUrls[chain];
|
|
2934
|
+
const cluster = chain.slice("solana:".length);
|
|
2935
|
+
return cluster === "devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com";
|
|
2936
|
+
}
|
|
2937
|
+
async function fetchBalance(opts) {
|
|
2938
|
+
const { kind, address, chain, rpcUrls } = opts;
|
|
2939
|
+
if (kind === "evm") {
|
|
2940
|
+
const rpcUrl = rpcUrls?.[chain] ?? DEFAULT_RPCS[chain];
|
|
2941
|
+
if (!rpcUrl) {
|
|
2942
|
+
throw new Error(
|
|
2943
|
+
`No RPC URL for ${chain}. Pass rpcUrls: { '${chain}': 'https://...' } in social config.`
|
|
2944
|
+
);
|
|
2945
|
+
}
|
|
2946
|
+
const { JsonRpcProvider, formatEther } = await import("ethers");
|
|
2947
|
+
const wei = await new JsonRpcProvider(rpcUrl).getBalance(address);
|
|
2948
|
+
return { raw: wei, formatted: formatEther(wei), symbol: EVM_SYMBOLS[chain] ?? "ETH", decimals: 18 };
|
|
2949
|
+
}
|
|
2950
|
+
const { Connection, PublicKey, LAMPORTS_PER_SOL } = await import("@solana/web3.js");
|
|
2951
|
+
const lamports = await new Connection(solanaEndpoint(chain, rpcUrls)).getBalance(
|
|
2952
|
+
new PublicKey(address)
|
|
2953
|
+
);
|
|
2954
|
+
return {
|
|
2955
|
+
raw: BigInt(lamports),
|
|
2956
|
+
formatted: String(lamports / LAMPORTS_PER_SOL),
|
|
2957
|
+
symbol: "SOL",
|
|
2958
|
+
decimals: 9
|
|
2959
|
+
};
|
|
2960
|
+
}
|
|
2961
|
+
function formatBalanceDisplay(value) {
|
|
2962
|
+
if (value == null) return "\u2014";
|
|
2963
|
+
const n = Number(value);
|
|
2964
|
+
if (!Number.isFinite(n)) return value;
|
|
2965
|
+
return n === 0 ? "0" : n < 1e-4 ? "<0.0001" : n.toFixed(4).replace(/\.?0+$/, "");
|
|
2966
|
+
}
|
|
2967
|
+
|
|
2968
|
+
// src/social/client.ts
|
|
2969
|
+
var DEFAULT_API_BASE = "https://backend.decane.app";
|
|
2970
|
+
var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
|
|
2971
|
+
var DEFAULT_SESSION_MINUTES = 30;
|
|
2904
2972
|
function makePersistKey(apiKey) {
|
|
2905
2973
|
return `decane:social:${apiKey.slice(0, 20)}`;
|
|
2906
2974
|
}
|
|
@@ -3398,6 +3466,23 @@ async function createDecaneConnect(config) {
|
|
|
3398
3466
|
const txResponse = await provider.broadcastTransaction(signedTx);
|
|
3399
3467
|
return txResponse.hash;
|
|
3400
3468
|
},
|
|
3469
|
+
async signTypedData(req) {
|
|
3470
|
+
const tee = session.requireActive();
|
|
3471
|
+
if (!req.chain.startsWith("evm:")) {
|
|
3472
|
+
throw new CallSequenceError("signTypedData is EVM-only (EIP-712).");
|
|
3473
|
+
}
|
|
3474
|
+
return signEvmTypedData(
|
|
3475
|
+
tee,
|
|
3476
|
+
req.chain,
|
|
3477
|
+
{
|
|
3478
|
+
domain: req.domain,
|
|
3479
|
+
types: req.types,
|
|
3480
|
+
message: req.message,
|
|
3481
|
+
primaryType: req.primaryType
|
|
3482
|
+
},
|
|
3483
|
+
auth?.jwt
|
|
3484
|
+
);
|
|
3485
|
+
},
|
|
3401
3486
|
async signSolanaTransaction(serializedTx) {
|
|
3402
3487
|
const tee = session.requireActive();
|
|
3403
3488
|
let tx;
|
|
@@ -3423,6 +3508,42 @@ async function createDecaneConnect(config) {
|
|
|
3423
3508
|
getAddresses() {
|
|
3424
3509
|
return auth?.addresses ?? persisted?.addresses ?? null;
|
|
3425
3510
|
},
|
|
3511
|
+
// Native-token balance. Read-only public chain data, so it works whenever an
|
|
3512
|
+
// address is known — including while the wallet is locked (no TEE session
|
|
3513
|
+
// needed). `chain` defaults to the first configured EVM chain, else the
|
|
3514
|
+
// first Solana chain.
|
|
3515
|
+
async getBalance(chain) {
|
|
3516
|
+
const addresses = auth?.addresses ?? persisted?.addresses;
|
|
3517
|
+
if (!addresses) throw new CallSequenceError("Not connected \u2014 no wallet address known");
|
|
3518
|
+
const resolvedChain = chain ?? config.chains.find((c) => c.startsWith("evm:")) ?? config.chains.find((c) => c.startsWith("solana:"));
|
|
3519
|
+
if (!resolvedChain) throw new CallSequenceError("No chain configured");
|
|
3520
|
+
const kind = resolvedChain.startsWith("solana:") ? "solana" : "evm";
|
|
3521
|
+
const address = kind === "evm" ? addresses.evm : addresses.solana;
|
|
3522
|
+
if (!address) throw new CallSequenceError(`This wallet has no ${kind} address`);
|
|
3523
|
+
return fetchBalance({ kind, address, chain: resolvedChain, rpcUrls: config.rpcUrls });
|
|
3524
|
+
},
|
|
3525
|
+
// Balances across every configured chain the wallet has an address for.
|
|
3526
|
+
// Per-chain failures resolve to null rather than rejecting the whole call,
|
|
3527
|
+
// so one dead RPC doesn't blank the entire list.
|
|
3528
|
+
async getBalances() {
|
|
3529
|
+
const addresses = auth?.addresses ?? persisted?.addresses;
|
|
3530
|
+
if (!addresses) throw new CallSequenceError("Not connected \u2014 no wallet address known");
|
|
3531
|
+
const targets = config.chains.filter((c) => {
|
|
3532
|
+
const kind = c.startsWith("solana:") ? "solana" : "evm";
|
|
3533
|
+
return kind === "evm" ? !!addresses.evm : !!addresses.solana;
|
|
3534
|
+
});
|
|
3535
|
+
return Promise.all(
|
|
3536
|
+
targets.map(async (chain) => {
|
|
3537
|
+
const kind = chain.startsWith("solana:") ? "solana" : "evm";
|
|
3538
|
+
const address = kind === "evm" ? addresses.evm : addresses.solana;
|
|
3539
|
+
try {
|
|
3540
|
+
return { chain, balance: await fetchBalance({ kind, address, chain, rpcUrls: config.rpcUrls }) };
|
|
3541
|
+
} catch {
|
|
3542
|
+
return { chain, balance: null };
|
|
3543
|
+
}
|
|
3544
|
+
})
|
|
3545
|
+
);
|
|
3546
|
+
},
|
|
3426
3547
|
async rotateShares(opts) {
|
|
3427
3548
|
if (!auth) throw new CallSequenceError("Not connected \u2014 call connect() first");
|
|
3428
3549
|
const tee = session.requireActive();
|
|
@@ -3669,6 +3790,31 @@ var CSS_VARS = {
|
|
|
3669
3790
|
|
|
3670
3791
|
// src/ui/icons.tsx
|
|
3671
3792
|
import React from "react";
|
|
3793
|
+
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";
|
|
3794
|
+
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";
|
|
3795
|
+
function DecaneMark({ size = 24, muted = false }) {
|
|
3796
|
+
const color = muted ? "var(--dc-text-muted)" : "var(--dc-accent)";
|
|
3797
|
+
return /* @__PURE__ */ React.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, style: { flexShrink: 0, display: "block" } }, /* @__PURE__ */ React.createElement("polygon", { points: DECAGON_OUTER, fill: color, fillOpacity: muted ? 0.08 : 0.1, stroke: color, strokeWidth: "1.4", strokeLinejoin: "round" }), /* @__PURE__ */ React.createElement("polygon", { points: DECAGON_INNER, fill: color, fillOpacity: muted ? 0.55 : 0.95 }));
|
|
3798
|
+
}
|
|
3799
|
+
function DecaneWordmark({ size = 15, muted = false }) {
|
|
3800
|
+
return /* @__PURE__ */ React.createElement(
|
|
3801
|
+
"span",
|
|
3802
|
+
{
|
|
3803
|
+
style: {
|
|
3804
|
+
fontFamily: "var(--dc-font-sans, system-ui, sans-serif)",
|
|
3805
|
+
fontWeight: 800,
|
|
3806
|
+
fontSize: size,
|
|
3807
|
+
letterSpacing: "-0.03em",
|
|
3808
|
+
color: muted ? "var(--dc-text-muted)" : "var(--dc-text)",
|
|
3809
|
+
lineHeight: 1
|
|
3810
|
+
}
|
|
3811
|
+
},
|
|
3812
|
+
"decane"
|
|
3813
|
+
);
|
|
3814
|
+
}
|
|
3815
|
+
function DecaneLogo({ size = 20, muted = false }) {
|
|
3816
|
+
return /* @__PURE__ */ React.createElement("span", { style: { display: "inline-flex", alignItems: "center", gap: size * 0.34 } }, /* @__PURE__ */ React.createElement(DecaneMark, { size, muted }), /* @__PURE__ */ React.createElement(DecaneWordmark, { size: size * 0.78, muted }));
|
|
3817
|
+
}
|
|
3672
3818
|
function WalletIcon({ src, name, size = 36 }) {
|
|
3673
3819
|
if (src) {
|
|
3674
3820
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -4622,40 +4768,17 @@ function useBalance(kind, address, chain, rpcUrls) {
|
|
|
4622
4768
|
if (!address || !chain) return;
|
|
4623
4769
|
let cancelled = false;
|
|
4624
4770
|
setState((s) => ({ ...s, loading: true }));
|
|
4625
|
-
(
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
if (!cancelled) setState({ loading: false, value: null, symbol: "ETH" });
|
|
4631
|
-
return;
|
|
4632
|
-
}
|
|
4633
|
-
const { JsonRpcProvider, formatEther } = await import("ethers");
|
|
4634
|
-
const wei = await new JsonRpcProvider(rpcUrl).getBalance(address);
|
|
4635
|
-
if (!cancelled) setState({ loading: false, value: formatEther(wei), symbol: "ETH" });
|
|
4636
|
-
} else {
|
|
4637
|
-
const cluster = chain.slice("solana:".length);
|
|
4638
|
-
const endpoint = rpcUrls?.[chain] ?? (cluster === "devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com");
|
|
4639
|
-
const { Connection, PublicKey, LAMPORTS_PER_SOL } = await import("@solana/web3.js");
|
|
4640
|
-
const lamports = await new Connection(endpoint).getBalance(new PublicKey(address));
|
|
4641
|
-
if (!cancelled) setState({ loading: false, value: String(lamports / LAMPORTS_PER_SOL), symbol: "SOL" });
|
|
4642
|
-
}
|
|
4643
|
-
} catch {
|
|
4644
|
-
if (!cancelled) setState({ loading: false, value: null, symbol: kind === "evm" ? "ETH" : "SOL" });
|
|
4645
|
-
}
|
|
4646
|
-
})();
|
|
4771
|
+
fetchBalance({ kind, address, chain, rpcUrls }).then((b) => {
|
|
4772
|
+
if (!cancelled) setState({ loading: false, value: b.formatted, symbol: b.symbol });
|
|
4773
|
+
}).catch(() => {
|
|
4774
|
+
if (!cancelled) setState({ loading: false, value: null, symbol: kind === "evm" ? "ETH" : "SOL" });
|
|
4775
|
+
});
|
|
4647
4776
|
return () => {
|
|
4648
4777
|
cancelled = true;
|
|
4649
4778
|
};
|
|
4650
4779
|
}, [kind, address, chain, rpcUrls]);
|
|
4651
4780
|
return state;
|
|
4652
4781
|
}
|
|
4653
|
-
function formatBalance(value) {
|
|
4654
|
-
if (value == null) return "\u2014";
|
|
4655
|
-
const n = Number(value);
|
|
4656
|
-
if (!Number.isFinite(n)) return value;
|
|
4657
|
-
return n === 0 ? "0" : n < 1e-4 ? "<0.0001" : n.toFixed(4).replace(/\.?0+$/, "");
|
|
4658
|
-
}
|
|
4659
4782
|
function AddressRow({
|
|
4660
4783
|
label,
|
|
4661
4784
|
address,
|
|
@@ -4671,7 +4794,7 @@ function AddressRow({
|
|
|
4671
4794
|
borderRadius: 10,
|
|
4672
4795
|
padding: "10px 14px",
|
|
4673
4796
|
marginBottom: 8
|
|
4674
|
-
} }, /* @__PURE__ */ React3.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 5 } }, /* @__PURE__ */ React3.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "0.06em", textTransform: "uppercase" } }, label), /* @__PURE__ */ React3.createElement("span", { style: { fontSize: 11, fontFamily: "monospace", color: "var(--dc-text)" } }, balance.loading ? "\u2026" : `${
|
|
4797
|
+
} }, /* @__PURE__ */ React3.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 5 } }, /* @__PURE__ */ React3.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "0.06em", textTransform: "uppercase" } }, label), /* @__PURE__ */ React3.createElement("span", { style: { fontSize: 11, fontFamily: "monospace", color: "var(--dc-text)" } }, balance.loading ? "\u2026" : `${formatBalanceDisplay(balance.value)} ${balance.symbol}`)), /* @__PURE__ */ React3.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 } }, /* @__PURE__ */ React3.createElement("span", { style: { fontSize: 13, fontFamily: "monospace", color: "var(--dc-text)", letterSpacing: "0.02em" } }, short), /* @__PURE__ */ React3.createElement(CopyButton, { value: address })));
|
|
4675
4798
|
}
|
|
4676
4799
|
function SignInView({
|
|
4677
4800
|
onGoogleSignIn,
|
|
@@ -5048,34 +5171,17 @@ function SocialWalletModal({
|
|
|
5048
5171
|
top: 0,
|
|
5049
5172
|
zIndex: 1,
|
|
5050
5173
|
background: "linear-gradient(90deg, transparent, var(--dc-accent) 30%, var(--dc-accent) 70%, transparent)"
|
|
5051
|
-
} }), /* @__PURE__ */ React3.createElement("div", { style: { padding: "18px 20px 16px", display: "flex", alignItems: "center", gap:
|
|
5052
|
-
width:
|
|
5053
|
-
height:
|
|
5054
|
-
borderRadius:
|
|
5174
|
+
} }), /* @__PURE__ */ React3.createElement("div", { style: { padding: "18px 20px 16px", display: "flex", alignItems: "center", gap: 11 } }, /* @__PURE__ */ React3.createElement("div", { style: {
|
|
5175
|
+
width: 38,
|
|
5176
|
+
height: 38,
|
|
5177
|
+
borderRadius: 11,
|
|
5055
5178
|
background: "var(--dc-surface)",
|
|
5056
5179
|
border: "1px solid var(--dc-border)",
|
|
5057
5180
|
display: "flex",
|
|
5058
5181
|
alignItems: "center",
|
|
5059
5182
|
justifyContent: "center",
|
|
5060
5183
|
flexShrink: 0
|
|
5061
|
-
} }, /* @__PURE__ */ React3.createElement("
|
|
5062
|
-
"path",
|
|
5063
|
-
{
|
|
5064
|
-
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",
|
|
5065
|
-
stroke: "var(--dc-accent)",
|
|
5066
|
-
strokeWidth: "1.4",
|
|
5067
|
-
strokeLinejoin: "round"
|
|
5068
|
-
}
|
|
5069
|
-
), /* @__PURE__ */ React3.createElement(
|
|
5070
|
-
"path",
|
|
5071
|
-
{
|
|
5072
|
-
d: "M5.5 9L7 10.5L10.5 7",
|
|
5073
|
-
stroke: "var(--dc-accent)",
|
|
5074
|
-
strokeWidth: "1.4",
|
|
5075
|
-
strokeLinecap: "round",
|
|
5076
|
-
strokeLinejoin: "round"
|
|
5077
|
-
}
|
|
5078
|
-
))), /* @__PURE__ */ React3.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React3.createElement("div", { style: { fontSize: 15, fontWeight: 800, color: "var(--dc-text)", letterSpacing: "-0.02em" } }, "Social Wallet"), /* @__PURE__ */ React3.createElement("div", { style: { fontSize: 11, color: "var(--dc-text-muted)", marginTop: 1 } }, "Decane non-custodial \xB7 key split three ways")), /* @__PURE__ */ React3.createElement(
|
|
5184
|
+
} }, /* @__PURE__ */ React3.createElement(DecaneMark, { size: 22 })), /* @__PURE__ */ React3.createElement("div", { style: { flex: 1 } }, /* @__PURE__ */ React3.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 6 } }, /* @__PURE__ */ React3.createElement(DecaneWordmark, { size: 15 }), /* @__PURE__ */ React3.createElement("span", { style: { fontSize: 13, fontWeight: 700, color: "var(--dc-text-muted)", letterSpacing: "-0.01em" } }, "wallet")), /* @__PURE__ */ React3.createElement("div", { style: { fontSize: 11, color: "var(--dc-text-muted)", marginTop: 2 } }, "Non-custodial \xB7 key split three ways")), /* @__PURE__ */ React3.createElement(
|
|
5079
5185
|
"button",
|
|
5080
5186
|
{
|
|
5081
5187
|
onClick: onClose,
|
|
@@ -5178,7 +5284,14 @@ function SocialWalletModal({
|
|
|
5178
5284
|
}
|
|
5179
5285
|
},
|
|
5180
5286
|
disconnecting ? "Signing out\u2026" : "Sign out"
|
|
5181
|
-
)))
|
|
5287
|
+
))), /* @__PURE__ */ React3.createElement("div", { style: {
|
|
5288
|
+
padding: "11px 16px",
|
|
5289
|
+
borderTop: "1px solid var(--dc-border)",
|
|
5290
|
+
display: "flex",
|
|
5291
|
+
alignItems: "center",
|
|
5292
|
+
justifyContent: "center",
|
|
5293
|
+
gap: 6
|
|
5294
|
+
} }, /* @__PURE__ */ React3.createElement("span", { style: { fontSize: 10.5, color: "var(--dc-text-muted)", letterSpacing: "0.02em" } }, "Secured by"), /* @__PURE__ */ React3.createElement(DecaneMark, { size: 13, muted: true }), /* @__PURE__ */ React3.createElement(DecaneWordmark, { size: 11, muted: true })))
|
|
5182
5295
|
);
|
|
5183
5296
|
return createPortal2(modal, document.body);
|
|
5184
5297
|
}
|
|
@@ -5371,6 +5484,21 @@ function DecaneKit({ config, children }) {
|
|
|
5371
5484
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
5372
5485
|
return sdk.signSolanaTransaction(tx);
|
|
5373
5486
|
}, []);
|
|
5487
|
+
const socialSignTypedData = useCallback3(async (req) => {
|
|
5488
|
+
const sdk = socialRef.current;
|
|
5489
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
5490
|
+
return sdk.signTypedData({ ...req, chain: req.chain });
|
|
5491
|
+
}, []);
|
|
5492
|
+
const socialGetBalance = useCallback3(async (chain) => {
|
|
5493
|
+
const sdk = socialRef.current;
|
|
5494
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
5495
|
+
return sdk.getBalance(chain);
|
|
5496
|
+
}, []);
|
|
5497
|
+
const socialGetBalances = useCallback3(async () => {
|
|
5498
|
+
const sdk = socialRef.current;
|
|
5499
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
5500
|
+
return sdk.getBalances();
|
|
5501
|
+
}, []);
|
|
5374
5502
|
const socialRotateShares = useCallback3(async (opts) => {
|
|
5375
5503
|
const sdk = socialRef.current;
|
|
5376
5504
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
@@ -5426,7 +5554,10 @@ function DecaneKit({ config, children }) {
|
|
|
5426
5554
|
socialDisconnect,
|
|
5427
5555
|
socialSignMessage,
|
|
5428
5556
|
socialSendTransaction,
|
|
5557
|
+
socialGetBalance,
|
|
5558
|
+
socialGetBalances,
|
|
5429
5559
|
socialSignSolanaTransaction,
|
|
5560
|
+
socialSignTypedData,
|
|
5430
5561
|
socialRotateShares,
|
|
5431
5562
|
socialExportPortableBackup,
|
|
5432
5563
|
socialHasRecoveryShare,
|
|
@@ -5624,6 +5755,9 @@ function useSocialWallet() {
|
|
|
5624
5755
|
socialSignMessage,
|
|
5625
5756
|
socialSendTransaction,
|
|
5626
5757
|
socialSignSolanaTransaction,
|
|
5758
|
+
socialSignTypedData,
|
|
5759
|
+
socialGetBalance,
|
|
5760
|
+
socialGetBalances,
|
|
5627
5761
|
socialRotateShares,
|
|
5628
5762
|
socialExportPortableBackup,
|
|
5629
5763
|
socialHasRecoveryShare,
|
|
@@ -5660,6 +5794,18 @@ function useSocialWallet() {
|
|
|
5660
5794
|
(tx) => run(() => socialSignSolanaTransaction(tx)),
|
|
5661
5795
|
[socialSignSolanaTransaction]
|
|
5662
5796
|
);
|
|
5797
|
+
const signTypedData = useCallback4(
|
|
5798
|
+
(req) => run(() => socialSignTypedData(req)),
|
|
5799
|
+
[socialSignTypedData]
|
|
5800
|
+
);
|
|
5801
|
+
const getBalance = useCallback4(
|
|
5802
|
+
(chain) => run(() => socialGetBalance(chain)),
|
|
5803
|
+
[socialGetBalance]
|
|
5804
|
+
);
|
|
5805
|
+
const getBalances = useCallback4(
|
|
5806
|
+
() => run(() => socialGetBalances()),
|
|
5807
|
+
[socialGetBalances]
|
|
5808
|
+
);
|
|
5663
5809
|
const unlock = useCallback4(async () => {
|
|
5664
5810
|
setError(null);
|
|
5665
5811
|
try {
|
|
@@ -5721,6 +5867,10 @@ function useSocialWallet() {
|
|
|
5721
5867
|
signMessage,
|
|
5722
5868
|
sendTransaction,
|
|
5723
5869
|
signSolanaTransaction: signSolanaTransaction2,
|
|
5870
|
+
signTypedData,
|
|
5871
|
+
// Balances (native token; read-only, works while locked)
|
|
5872
|
+
getBalance,
|
|
5873
|
+
getBalances,
|
|
5724
5874
|
// Recovery (2-of-3 Shamir share set)
|
|
5725
5875
|
rotateShares,
|
|
5726
5876
|
exportPortableBackup,
|
|
@@ -5732,6 +5882,52 @@ function useSocialWallet() {
|
|
|
5732
5882
|
clearError: () => setError(null)
|
|
5733
5883
|
};
|
|
5734
5884
|
}
|
|
5885
|
+
function useSocialBalance(chain) {
|
|
5886
|
+
const { socialAuth, socialGetBalance } = useDecaneContext();
|
|
5887
|
+
const [balance, setBalance] = useState4(null);
|
|
5888
|
+
const [loading, setLoading] = useState4(false);
|
|
5889
|
+
const [error, setError] = useState4(null);
|
|
5890
|
+
const addrKey = `${socialAuth.addresses?.evm ?? ""}|${socialAuth.addresses?.solana ?? ""}`;
|
|
5891
|
+
const refetch = useCallback4(async () => {
|
|
5892
|
+
if (!socialAuth.addresses) {
|
|
5893
|
+
setBalance(null);
|
|
5894
|
+
return;
|
|
5895
|
+
}
|
|
5896
|
+
setLoading(true);
|
|
5897
|
+
setError(null);
|
|
5898
|
+
try {
|
|
5899
|
+
setBalance(await socialGetBalance(chain));
|
|
5900
|
+
} catch (e) {
|
|
5901
|
+
setError(e.message);
|
|
5902
|
+
setBalance(null);
|
|
5903
|
+
} finally {
|
|
5904
|
+
setLoading(false);
|
|
5905
|
+
}
|
|
5906
|
+
}, [socialGetBalance, chain, socialAuth.addresses]);
|
|
5907
|
+
useEffect4(() => {
|
|
5908
|
+
let cancelled = false;
|
|
5909
|
+
if (!socialAuth.addresses) {
|
|
5910
|
+
setBalance(null);
|
|
5911
|
+
return;
|
|
5912
|
+
}
|
|
5913
|
+
setLoading(true);
|
|
5914
|
+
setError(null);
|
|
5915
|
+
socialGetBalance(chain).then((b) => {
|
|
5916
|
+
if (!cancelled) setBalance(b);
|
|
5917
|
+
}).catch((e) => {
|
|
5918
|
+
if (!cancelled) {
|
|
5919
|
+
setError(e.message);
|
|
5920
|
+
setBalance(null);
|
|
5921
|
+
}
|
|
5922
|
+
}).finally(() => {
|
|
5923
|
+
if (!cancelled) setLoading(false);
|
|
5924
|
+
});
|
|
5925
|
+
return () => {
|
|
5926
|
+
cancelled = true;
|
|
5927
|
+
};
|
|
5928
|
+
}, [addrKey, chain]);
|
|
5929
|
+
return { balance, loading, error, refetch };
|
|
5930
|
+
}
|
|
5735
5931
|
function toDecaneError(err) {
|
|
5736
5932
|
if (err instanceof DecaneError) return err;
|
|
5737
5933
|
const msg = err instanceof Error ? err.message : err?.message != null ? String(err.message) : String(err);
|
|
@@ -5964,6 +6160,9 @@ export {
|
|
|
5964
6160
|
DecaneError,
|
|
5965
6161
|
DecaneErrorCode,
|
|
5966
6162
|
DecaneKit,
|
|
6163
|
+
DecaneLogo,
|
|
6164
|
+
DecaneMark,
|
|
6165
|
+
DecaneWordmark,
|
|
5967
6166
|
ExportNotAuthorizedError,
|
|
5968
6167
|
InvalidApiKeyError,
|
|
5969
6168
|
InvalidPinError,
|
|
@@ -5992,6 +6191,7 @@ export {
|
|
|
5992
6191
|
useSignMessage,
|
|
5993
6192
|
useSignTypedData,
|
|
5994
6193
|
useSocialAuth,
|
|
6194
|
+
useSocialBalance,
|
|
5995
6195
|
useSocialWallet,
|
|
5996
6196
|
useWalletSelector,
|
|
5997
6197
|
verifyEmailCode
|