decane-connect-kit 2.2.8 → 2.3.1

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.d.cts CHANGED
@@ -294,6 +294,39 @@ interface BalanceResult {
294
294
  decimals: number;
295
295
  }
296
296
 
297
+ interface Eip1193Provider {
298
+ request(args: {
299
+ method: string;
300
+ params?: unknown[] | object;
301
+ }): Promise<unknown>;
302
+ on(event: string, handler: (...args: unknown[]) => void): this;
303
+ removeListener(event: string, handler: (...args: unknown[]) => void): this;
304
+ /** Marks this as the Decane provider (parallel to wallets' isMetaMask etc.). */
305
+ readonly isDecane: true;
306
+ }
307
+ interface EthereumProviderOptions {
308
+ /** Initial chain id (numeric). Defaults to the first configured EVM chain, else 1. */
309
+ chainId?: number;
310
+ /** Per-chain RPC overrides ('evm:8453' -> url). Falls back to Decane's defaults. */
311
+ rpcUrls?: Record<string, string>;
312
+ }
313
+ /**
314
+ * Build an EIP-1193 provider over a connected Decane social client.
315
+ *
316
+ * `signAuthorization` (EIP-7702) is wired only when the client exposes it — that
317
+ * requires the TEE signer to support the authorization signing path.
318
+ */
319
+ declare function createEthereumProvider(client: DecaneConnect, opts?: EthereumProviderOptions): Eip1193Provider;
320
+
321
+ interface SignedAuthorization {
322
+ chainId: number;
323
+ address: string;
324
+ nonce: number;
325
+ yParity: number;
326
+ r: string;
327
+ s: string;
328
+ }
329
+
297
330
  type Chain = `evm:${number}` | `solana:${'mainnet' | 'devnet'}`;
298
331
  interface DecaneConnectConfig {
299
332
  /** Dashboard project ID (public). Sent with every request so the backend can
@@ -446,6 +479,36 @@ interface DecaneConnect {
446
479
  sendTransaction(req: SendTransactionRequest): Promise<string>;
447
480
  /** Sign EIP-712 typed data (EVM only). Throws on a Solana chain. */
448
481
  signTypedData(req: SignTypedDataRequest): Promise<string>;
482
+ /**
483
+ * A standard EIP-1193 Ethereum provider backed by this wallet — drop it into
484
+ * viem (`custom(provider)`), wagmi, or ethers (`BrowserProvider`). Signing
485
+ * goes through the TEE; reads are forwarded to the chain RPC. Memoized, so
486
+ * repeated calls return the same instance (safe for wagmi).
487
+ */
488
+ getEthereumProvider(opts?: {
489
+ chainId?: number;
490
+ }): Eip1193Provider;
491
+ /**
492
+ * Sign an EIP-7702 authorization, delegating this EOA to a smart-account
493
+ * implementation contract on `chainId`. Enables account-abstraction /
494
+ * sponsored-gas flows. Returns the full viem `SignedAuthorization` tuple, so
495
+ * it drops straight into a userOperation's `authorization` field or a type-4
496
+ * transaction's authorizationList. `address` and `contractAddress` are
497
+ * interchangeable (the latter matches Privy's/older viem's param name).
498
+ */
499
+ signAuthorization(req: {
500
+ chainId: number;
501
+ address?: string;
502
+ contractAddress?: string;
503
+ nonce: number;
504
+ }): Promise<SignedAuthorization>;
505
+ /**
506
+ * The current session's access token (the Decane JWT). Use it to authenticate
507
+ * the user to your own backend (e.g. a sponsored-bundler proxy); verify it
508
+ * server-side against backend.decane.app/.well-known/jwks.json. Null with no
509
+ * live session.
510
+ */
511
+ getAccessToken(): string | null;
449
512
  signSolanaTransaction(tx: Uint8Array): Promise<Uint8Array>;
450
513
  disconnect(): Promise<void>;
451
514
  getAddresses(): {
@@ -866,6 +929,16 @@ declare function useSocialWallet(): {
866
929
  chain: string;
867
930
  balance: BalanceResult | null;
868
931
  }[]>;
932
+ signAuthorization: (req: {
933
+ chainId: number;
934
+ address?: string;
935
+ contractAddress?: string;
936
+ nonce: number;
937
+ }) => Promise<SignedAuthorization>;
938
+ getEthereumProvider: (opts?: {
939
+ chainId?: number;
940
+ }) => Eip1193Provider;
941
+ getAccessToken: () => string | null;
869
942
  rotateShares: (opts: {
870
943
  password: string;
871
944
  passwordHint?: string;
@@ -887,6 +960,9 @@ declare function useSocialBalance(chain?: string): {
887
960
  error: string | null;
888
961
  refetch: () => Promise<void>;
889
962
  };
963
+ declare function useEthereumProvider(opts?: {
964
+ chainId?: number;
965
+ }): Eip1193Provider | null;
890
966
  declare function useDecane(): {
891
967
  provider: DecaneProvider;
892
968
  wallets: UnifiedWalletAccount[];
@@ -959,4 +1035,4 @@ declare function useSignTypedData(): {
959
1035
  reset: () => void;
960
1036
  };
961
1037
 
962
- export { type ActiveSession, AttestationError, type AuthResult, BUILT_IN_CHAINS, type BalanceResult, type CAIP25Method, type CAIP25SessionRequest, type CAIP25SessionResult, CHAINS, CallSequenceError, type Chain, type ChainDescriptor, type ChainId, type ChainScope, type ChainSupport, type ChainType, type ConnectMode, type ConnectResult, type DecaneConfig, type DecaneConnect, type DecaneConnectConfig, DecaneConnectError, DecaneError, DecaneErrorCode, DecaneKit, DecaneLogo, DecaneMark, type DecaneProvider, DecaneWordmark, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SocialAuthState, type SocialConfig, SocialWalletModal, type Theme, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, startEmailAuth, useChainSwitch, useDecane, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
1038
+ export { type ActiveSession, AttestationError, type AuthResult, BUILT_IN_CHAINS, type BalanceResult, type CAIP25Method, type CAIP25SessionRequest, type CAIP25SessionResult, CHAINS, CallSequenceError, type Chain, type ChainDescriptor, type ChainId, type ChainScope, type ChainSupport, type ChainType, type ConnectMode, type ConnectResult, type DecaneConfig, type DecaneConnect, type DecaneConnectConfig, DecaneConnectError, DecaneError, DecaneErrorCode, DecaneKit, DecaneLogo, DecaneMark, type DecaneProvider, DecaneWordmark, type Eip1193Provider, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SignedAuthorization, type SocialAuthState, type SocialConfig, SocialWalletModal, type Theme, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, createEthereumProvider, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
package/dist/index.d.ts CHANGED
@@ -294,6 +294,39 @@ interface BalanceResult {
294
294
  decimals: number;
295
295
  }
296
296
 
297
+ interface Eip1193Provider {
298
+ request(args: {
299
+ method: string;
300
+ params?: unknown[] | object;
301
+ }): Promise<unknown>;
302
+ on(event: string, handler: (...args: unknown[]) => void): this;
303
+ removeListener(event: string, handler: (...args: unknown[]) => void): this;
304
+ /** Marks this as the Decane provider (parallel to wallets' isMetaMask etc.). */
305
+ readonly isDecane: true;
306
+ }
307
+ interface EthereumProviderOptions {
308
+ /** Initial chain id (numeric). Defaults to the first configured EVM chain, else 1. */
309
+ chainId?: number;
310
+ /** Per-chain RPC overrides ('evm:8453' -> url). Falls back to Decane's defaults. */
311
+ rpcUrls?: Record<string, string>;
312
+ }
313
+ /**
314
+ * Build an EIP-1193 provider over a connected Decane social client.
315
+ *
316
+ * `signAuthorization` (EIP-7702) is wired only when the client exposes it — that
317
+ * requires the TEE signer to support the authorization signing path.
318
+ */
319
+ declare function createEthereumProvider(client: DecaneConnect, opts?: EthereumProviderOptions): Eip1193Provider;
320
+
321
+ interface SignedAuthorization {
322
+ chainId: number;
323
+ address: string;
324
+ nonce: number;
325
+ yParity: number;
326
+ r: string;
327
+ s: string;
328
+ }
329
+
297
330
  type Chain = `evm:${number}` | `solana:${'mainnet' | 'devnet'}`;
298
331
  interface DecaneConnectConfig {
299
332
  /** Dashboard project ID (public). Sent with every request so the backend can
@@ -446,6 +479,36 @@ interface DecaneConnect {
446
479
  sendTransaction(req: SendTransactionRequest): Promise<string>;
447
480
  /** Sign EIP-712 typed data (EVM only). Throws on a Solana chain. */
448
481
  signTypedData(req: SignTypedDataRequest): Promise<string>;
482
+ /**
483
+ * A standard EIP-1193 Ethereum provider backed by this wallet — drop it into
484
+ * viem (`custom(provider)`), wagmi, or ethers (`BrowserProvider`). Signing
485
+ * goes through the TEE; reads are forwarded to the chain RPC. Memoized, so
486
+ * repeated calls return the same instance (safe for wagmi).
487
+ */
488
+ getEthereumProvider(opts?: {
489
+ chainId?: number;
490
+ }): Eip1193Provider;
491
+ /**
492
+ * Sign an EIP-7702 authorization, delegating this EOA to a smart-account
493
+ * implementation contract on `chainId`. Enables account-abstraction /
494
+ * sponsored-gas flows. Returns the full viem `SignedAuthorization` tuple, so
495
+ * it drops straight into a userOperation's `authorization` field or a type-4
496
+ * transaction's authorizationList. `address` and `contractAddress` are
497
+ * interchangeable (the latter matches Privy's/older viem's param name).
498
+ */
499
+ signAuthorization(req: {
500
+ chainId: number;
501
+ address?: string;
502
+ contractAddress?: string;
503
+ nonce: number;
504
+ }): Promise<SignedAuthorization>;
505
+ /**
506
+ * The current session's access token (the Decane JWT). Use it to authenticate
507
+ * the user to your own backend (e.g. a sponsored-bundler proxy); verify it
508
+ * server-side against backend.decane.app/.well-known/jwks.json. Null with no
509
+ * live session.
510
+ */
511
+ getAccessToken(): string | null;
449
512
  signSolanaTransaction(tx: Uint8Array): Promise<Uint8Array>;
450
513
  disconnect(): Promise<void>;
451
514
  getAddresses(): {
@@ -866,6 +929,16 @@ declare function useSocialWallet(): {
866
929
  chain: string;
867
930
  balance: BalanceResult | null;
868
931
  }[]>;
932
+ signAuthorization: (req: {
933
+ chainId: number;
934
+ address?: string;
935
+ contractAddress?: string;
936
+ nonce: number;
937
+ }) => Promise<SignedAuthorization>;
938
+ getEthereumProvider: (opts?: {
939
+ chainId?: number;
940
+ }) => Eip1193Provider;
941
+ getAccessToken: () => string | null;
869
942
  rotateShares: (opts: {
870
943
  password: string;
871
944
  passwordHint?: string;
@@ -887,6 +960,9 @@ declare function useSocialBalance(chain?: string): {
887
960
  error: string | null;
888
961
  refetch: () => Promise<void>;
889
962
  };
963
+ declare function useEthereumProvider(opts?: {
964
+ chainId?: number;
965
+ }): Eip1193Provider | null;
890
966
  declare function useDecane(): {
891
967
  provider: DecaneProvider;
892
968
  wallets: UnifiedWalletAccount[];
@@ -959,4 +1035,4 @@ declare function useSignTypedData(): {
959
1035
  reset: () => void;
960
1036
  };
961
1037
 
962
- export { type ActiveSession, AttestationError, type AuthResult, BUILT_IN_CHAINS, type BalanceResult, type CAIP25Method, type CAIP25SessionRequest, type CAIP25SessionResult, CHAINS, CallSequenceError, type Chain, type ChainDescriptor, type ChainId, type ChainScope, type ChainSupport, type ChainType, type ConnectMode, type ConnectResult, type DecaneConfig, type DecaneConnect, type DecaneConnectConfig, DecaneConnectError, DecaneError, DecaneErrorCode, DecaneKit, DecaneLogo, DecaneMark, type DecaneProvider, DecaneWordmark, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SocialAuthState, type SocialConfig, SocialWalletModal, type Theme, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, startEmailAuth, useChainSwitch, useDecane, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
1038
+ export { type ActiveSession, AttestationError, type AuthResult, BUILT_IN_CHAINS, type BalanceResult, type CAIP25Method, type CAIP25SessionRequest, type CAIP25SessionResult, CHAINS, CallSequenceError, type Chain, type ChainDescriptor, type ChainId, type ChainScope, type ChainSupport, type ChainType, type ConnectMode, type ConnectResult, type DecaneConfig, type DecaneConnect, type DecaneConnectConfig, DecaneConnectError, DecaneError, DecaneErrorCode, DecaneKit, DecaneLogo, DecaneMark, type DecaneProvider, DecaneWordmark, type Eip1193Provider, type EthereumProviderOptions, ExportNotAuthorizedError, InvalidApiKeyError, InvalidPinError, InvalidRecoveryFileError, NetworkError, NewDeviceError, OriginNotAllowedError, type PortableBackup, PromptPinNotConfiguredError, ReconnectRequiredError, RecoveryFailedError, type RecoveryProgress, type RecoveryShareFile, RecoveryWalletMismatchError, type SdkEvent, type SendTransactionRequest, SessionExpiredError, ShareCorruptedError, type SignMessageRequest, type SignTypedDataRequest, type SignedAuthorization, type SocialAuthState, type SocialConfig, SocialWalletModal, type Theme, type TxParams, type UnifiedWalletAccount, UnlockRequiredError, UserCancelledError, WalletSelector, WebAuthnNotSupportedError, type WrappedShareMeta, WrongPasswordError, createDecane, createDecaneConnect, createEthereumProvider, startEmailAuth, useChainSwitch, useDecane, useEthereumProvider, useSendTransaction, useSignMessage, useSignTypedData, useSocialAuth, useSocialBalance, useSocialWallet, useWalletSelector, verifyEmailCode };
package/dist/index.js CHANGED
@@ -2705,6 +2705,17 @@ async function signEvmTransaction(tee, chain, tx, jwt) {
2705
2705
  async function signEvmMessage(tee, chain, message, jwt) {
2706
2706
  return tee.sign({ chain, kind: "message", payload: message }, jwt);
2707
2707
  }
2708
+ async function signEvmAuthorization(tee, chainId, address, nonce, jwt) {
2709
+ const serialized = await tee.sign(
2710
+ { chain: `evm:${chainId}`, kind: "authorization", payload: JSON.stringify({ chainId, address, nonce }) },
2711
+ jwt
2712
+ );
2713
+ const hex = serialized.startsWith("0x") ? serialized.slice(2) : serialized;
2714
+ const r = "0x" + hex.slice(0, 64);
2715
+ const s = "0x" + hex.slice(64, 128);
2716
+ const v = parseInt(hex.slice(128, 130), 16);
2717
+ return { chainId, address, nonce, yParity: v >= 27 ? v - 27 : v, r, s };
2718
+ }
2708
2719
  async function signEvmTypedData(tee, chain, typedData, jwt) {
2709
2720
  const payload = JSON.stringify(
2710
2721
  typedData,
@@ -2713,6 +2724,191 @@ async function signEvmTypedData(tee, chain, typedData, jwt) {
2713
2724
  return tee.sign({ chain, kind: "typedData", payload }, jwt);
2714
2725
  }
2715
2726
 
2727
+ // src/social/balance.ts
2728
+ var DEFAULT_RPCS = {
2729
+ "evm:1": "https://ethereum.publicnode.com",
2730
+ "evm:137": "https://polygon.publicnode.com",
2731
+ "evm:8453": "https://base.publicnode.com",
2732
+ "evm:10": "https://optimism.publicnode.com",
2733
+ "evm:42161": "https://arbitrum-one.publicnode.com",
2734
+ "evm:56": "https://bsc.publicnode.com",
2735
+ "evm:11155111": "https://ethereum-sepolia.publicnode.com",
2736
+ "evm:84532": "https://base-sepolia.publicnode.com",
2737
+ "evm:31337": "http://localhost:8545"
2738
+ };
2739
+ var EVM_SYMBOLS = {
2740
+ "evm:137": "MATIC",
2741
+ "evm:56": "BNB"
2742
+ };
2743
+ function solanaEndpoint(chain, rpcUrls) {
2744
+ if (rpcUrls?.[chain]) return rpcUrls[chain];
2745
+ const cluster = chain.slice("solana:".length);
2746
+ return cluster === "devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com";
2747
+ }
2748
+ async function fetchBalance(opts) {
2749
+ const { kind, address, chain, rpcUrls } = opts;
2750
+ if (kind === "evm") {
2751
+ const rpcUrl = rpcUrls?.[chain] ?? DEFAULT_RPCS[chain];
2752
+ if (!rpcUrl) {
2753
+ throw new Error(
2754
+ `No RPC URL for ${chain}. Pass rpcUrls: { '${chain}': 'https://...' } in social config.`
2755
+ );
2756
+ }
2757
+ const { JsonRpcProvider, formatEther } = await import("ethers");
2758
+ const wei = await new JsonRpcProvider(rpcUrl).getBalance(address);
2759
+ return { raw: wei, formatted: formatEther(wei), symbol: EVM_SYMBOLS[chain] ?? "ETH", decimals: 18 };
2760
+ }
2761
+ const { Connection, PublicKey, LAMPORTS_PER_SOL } = await import("@solana/web3.js");
2762
+ const lamports = await new Connection(solanaEndpoint(chain, rpcUrls)).getBalance(
2763
+ new PublicKey(address)
2764
+ );
2765
+ return {
2766
+ raw: BigInt(lamports),
2767
+ formatted: String(lamports / LAMPORTS_PER_SOL),
2768
+ symbol: "SOL",
2769
+ decimals: 9
2770
+ };
2771
+ }
2772
+ function formatBalanceDisplay(value) {
2773
+ if (value == null) return "\u2014";
2774
+ const n = Number(value);
2775
+ if (!Number.isFinite(n)) return value;
2776
+ return n === 0 ? "0" : n < 1e-4 ? "<0.0001" : n.toFixed(4).replace(/\.?0+$/, "");
2777
+ }
2778
+
2779
+ // src/social/eip1193.ts
2780
+ function toHex(n) {
2781
+ return "0x" + n.toString(16);
2782
+ }
2783
+ function hexToBytes2(hex) {
2784
+ const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
2785
+ const bytes = new Uint8Array(clean.length / 2);
2786
+ for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(clean.substr(i * 2, 2), 16);
2787
+ return bytes;
2788
+ }
2789
+ function asBigInt(v) {
2790
+ if (v == null) return void 0;
2791
+ if (typeof v === "bigint") return v;
2792
+ if (typeof v === "number") return BigInt(v);
2793
+ if (typeof v === "string") return BigInt(v);
2794
+ return void 0;
2795
+ }
2796
+ function createEthereumProvider(client, opts = {}) {
2797
+ let chainId = opts.chainId ?? 1;
2798
+ const listeners = /* @__PURE__ */ new Map();
2799
+ function emit(event, ...args) {
2800
+ listeners.get(event)?.forEach((h) => {
2801
+ try {
2802
+ h(...args);
2803
+ } catch {
2804
+ }
2805
+ });
2806
+ }
2807
+ client.on("connected", () => {
2808
+ const evm = client.getAddresses()?.evm;
2809
+ emit("connect", { chainId: toHex(chainId) });
2810
+ if (evm) emit("accountsChanged", [evm]);
2811
+ });
2812
+ client.on("disconnected", () => {
2813
+ emit("accountsChanged", []);
2814
+ emit("disconnect", { code: 4900, message: "Wallet disconnected" });
2815
+ });
2816
+ const chainStr = () => `evm:${chainId}`;
2817
+ async function rpc(method, params) {
2818
+ const url = opts.rpcUrls?.[`evm:${chainId}`] ?? DEFAULT_RPCS[`evm:${chainId}`];
2819
+ if (!url) {
2820
+ throw Object.assign(new Error(`No RPC for chain ${chainId}. Pass rpcUrls.`), { code: 4900 });
2821
+ }
2822
+ let res;
2823
+ try {
2824
+ res = await fetch(url, {
2825
+ method: "POST",
2826
+ headers: { "Content-Type": "application/json" },
2827
+ body: JSON.stringify({ jsonrpc: "2.0", id: Date.now(), method, params })
2828
+ });
2829
+ } catch (e) {
2830
+ throw Object.assign(new Error(`RPC request failed: ${e.message}`), { code: 4900 });
2831
+ }
2832
+ const json = await res.json();
2833
+ if (json.error) throw Object.assign(new Error(json.error.message), { code: json.error.code });
2834
+ return json.result;
2835
+ }
2836
+ async function request(args) {
2837
+ const params = Array.isArray(args.params) ? args.params : args.params ? [args.params] : [];
2838
+ const addr = () => client.getAddresses()?.evm ?? null;
2839
+ switch (args.method) {
2840
+ case "eth_requestAccounts":
2841
+ case "eth_accounts": {
2842
+ const a = addr();
2843
+ return a ? [a] : [];
2844
+ }
2845
+ case "eth_chainId":
2846
+ return toHex(chainId);
2847
+ case "net_version":
2848
+ return String(chainId);
2849
+ case "personal_sign": {
2850
+ const message = params[0];
2851
+ const bytes = typeof message === "string" && message.startsWith("0x") ? hexToBytes2(message) : message;
2852
+ return client.signMessage({ chain: chainStr(), message: bytes });
2853
+ }
2854
+ case "eth_signTypedData_v4":
2855
+ case "eth_signTypedData": {
2856
+ const raw = params[1];
2857
+ const td = typeof raw === "string" ? JSON.parse(raw) : raw;
2858
+ return client.signTypedData({
2859
+ chain: chainStr(),
2860
+ domain: td.domain,
2861
+ types: td.types,
2862
+ message: td.message,
2863
+ primaryType: td.primaryType
2864
+ });
2865
+ }
2866
+ case "eth_sendTransaction": {
2867
+ const tx = params[0];
2868
+ return client.sendTransaction({
2869
+ chain: chainStr(),
2870
+ to: tx.to,
2871
+ value: asBigInt(tx.value),
2872
+ data: tx.data ?? tx.input,
2873
+ gasLimit: asBigInt(tx.gas ?? tx.gasLimit)
2874
+ });
2875
+ }
2876
+ case "eth_signAuthorization":
2877
+ case "wallet_sign7702Authorization": {
2878
+ const p = params[0];
2879
+ const cid = p.chainId != null ? Number(asBigInt(p.chainId)) : chainId;
2880
+ const address = p.address ?? p.contractAddress;
2881
+ const nonce = p.nonce != null ? Number(asBigInt(p.nonce)) : 0;
2882
+ return client.signAuthorization({ chainId: cid, address, nonce });
2883
+ }
2884
+ case "wallet_switchEthereumChain": {
2885
+ const p = params[0];
2886
+ chainId = Number(asBigInt(p.chainId));
2887
+ emit("chainChanged", toHex(chainId));
2888
+ return null;
2889
+ }
2890
+ case "wallet_addEthereumChain":
2891
+ return null;
2892
+ default:
2893
+ return rpc(args.method, params);
2894
+ }
2895
+ }
2896
+ const provider = {
2897
+ request,
2898
+ on(event, handler) {
2899
+ if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());
2900
+ listeners.get(event).add(handler);
2901
+ return this;
2902
+ },
2903
+ removeListener(event, handler) {
2904
+ listeners.get(event)?.delete(handler);
2905
+ return this;
2906
+ },
2907
+ isDecane: true
2908
+ };
2909
+ return provider;
2910
+ }
2911
+
2716
2912
  // src/social/signers/solana.ts
2717
2913
  import { VersionedTransaction as VTx } from "@solana/web3.js";
2718
2914
  function b64(bytes) {
@@ -2950,58 +3146,6 @@ async function buildPortableBackup(deviceShare, recoveryShare, password, address
2950
3146
  };
2951
3147
  }
2952
3148
 
2953
- // src/social/balance.ts
2954
- var DEFAULT_RPCS = {
2955
- "evm:1": "https://ethereum.publicnode.com",
2956
- "evm:137": "https://polygon.publicnode.com",
2957
- "evm:8453": "https://base.publicnode.com",
2958
- "evm:10": "https://optimism.publicnode.com",
2959
- "evm:42161": "https://arbitrum-one.publicnode.com",
2960
- "evm:56": "https://bsc.publicnode.com",
2961
- "evm:11155111": "https://ethereum-sepolia.publicnode.com",
2962
- "evm:84532": "https://base-sepolia.publicnode.com",
2963
- "evm:31337": "http://localhost:8545"
2964
- };
2965
- var EVM_SYMBOLS = {
2966
- "evm:137": "MATIC",
2967
- "evm:56": "BNB"
2968
- };
2969
- function solanaEndpoint(chain, rpcUrls) {
2970
- if (rpcUrls?.[chain]) return rpcUrls[chain];
2971
- const cluster = chain.slice("solana:".length);
2972
- return cluster === "devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com";
2973
- }
2974
- async function fetchBalance(opts) {
2975
- const { kind, address, chain, rpcUrls } = opts;
2976
- if (kind === "evm") {
2977
- const rpcUrl = rpcUrls?.[chain] ?? DEFAULT_RPCS[chain];
2978
- if (!rpcUrl) {
2979
- throw new Error(
2980
- `No RPC URL for ${chain}. Pass rpcUrls: { '${chain}': 'https://...' } in social config.`
2981
- );
2982
- }
2983
- const { JsonRpcProvider, formatEther } = await import("ethers");
2984
- const wei = await new JsonRpcProvider(rpcUrl).getBalance(address);
2985
- return { raw: wei, formatted: formatEther(wei), symbol: EVM_SYMBOLS[chain] ?? "ETH", decimals: 18 };
2986
- }
2987
- const { Connection, PublicKey, LAMPORTS_PER_SOL } = await import("@solana/web3.js");
2988
- const lamports = await new Connection(solanaEndpoint(chain, rpcUrls)).getBalance(
2989
- new PublicKey(address)
2990
- );
2991
- return {
2992
- raw: BigInt(lamports),
2993
- formatted: String(lamports / LAMPORTS_PER_SOL),
2994
- symbol: "SOL",
2995
- decimals: 9
2996
- };
2997
- }
2998
- function formatBalanceDisplay(value) {
2999
- if (value == null) return "\u2014";
3000
- const n = Number(value);
3001
- if (!Number.isFinite(n)) return value;
3002
- return n === 0 ? "0" : n < 1e-4 ? "<0.0001" : n.toFixed(4).replace(/\.?0+$/, "");
3003
- }
3004
-
3005
3149
  // src/social/client.ts
3006
3150
  var DEFAULT_API_BASE = "https://backend.decane.app";
3007
3151
  var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
@@ -3074,6 +3218,7 @@ async function createDecaneConnect(config) {
3074
3218
  );
3075
3219
  let auth = null;
3076
3220
  let persisted = loadPersisted(PERSIST_KEY);
3221
+ let ethProvider = null;
3077
3222
  const persistSession = config.persistSession !== false;
3078
3223
  const SESSION_KEY = sessionPersistKey(config.apiKey);
3079
3224
  function persistLiveSession() {
@@ -3220,7 +3365,7 @@ async function createDecaneConnect(config) {
3220
3365
  let evmAddress;
3221
3366
  let solanaAddress;
3222
3367
  try {
3223
- evmAddress = new Wallet(toHex(master)).address;
3368
+ evmAddress = new Wallet(toHex2(master)).address;
3224
3369
  solanaAddress = Keypair.fromSeed(master).publicKey.toBase58();
3225
3370
  shareSet = await splitMaster(master, 1);
3226
3371
  } finally {
@@ -3581,6 +3726,30 @@ async function createDecaneConnect(config) {
3581
3726
  auth?.jwt
3582
3727
  );
3583
3728
  },
3729
+ async signAuthorization(req) {
3730
+ const tee = session.requireActive();
3731
+ const delegate = req.address ?? req.contractAddress;
3732
+ if (!delegate) throw new CallSequenceError("signAuthorization requires `address` (the delegate contract).");
3733
+ return signEvmAuthorization(tee, req.chainId, delegate, req.nonce, auth?.jwt);
3734
+ },
3735
+ // The current session's access token (the Decane JWT), for authenticating
3736
+ // the user to your own backend — e.g. a sponsored-bundler proxy. Verify it
3737
+ // server-side against https://backend.decane.app/.well-known/jwks.json.
3738
+ // Null when there is no live session.
3739
+ getAccessToken() {
3740
+ return auth?.jwt ?? null;
3741
+ },
3742
+ getEthereumProvider(opts) {
3743
+ if (!ethProvider) {
3744
+ const firstEvm = config.chains.find((c) => c.startsWith("evm:"));
3745
+ const defaultChainId = firstEvm ? parseInt(firstEvm.slice(4), 10) : 1;
3746
+ ethProvider = createEthereumProvider(client, {
3747
+ chainId: opts?.chainId ?? defaultChainId,
3748
+ rpcUrls: config.rpcUrls
3749
+ });
3750
+ }
3751
+ return ethProvider;
3752
+ },
3584
3753
  async signSolanaTransaction(serializedTx) {
3585
3754
  const tee = session.requireActive();
3586
3755
  let tx;
@@ -3744,14 +3913,14 @@ function b64uToBuffer(b64u) {
3744
3913
  const b644 = b64u.replace(/-/g, "+").replace(/_/g, "/");
3745
3914
  return Uint8Array.from(atob(b644), (c) => c.charCodeAt(0));
3746
3915
  }
3747
- function toHex(bytes) {
3916
+ function toHex2(bytes) {
3748
3917
  return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
3749
3918
  }
3750
3919
  async function deriveAddressesFromShares(a, b) {
3751
3920
  const master = await combineShares(a, b);
3752
3921
  try {
3753
3922
  return {
3754
- evm: new Wallet(toHex(master)).address,
3923
+ evm: new Wallet(toHex2(master)).address,
3755
3924
  solana: Keypair.fromSeed(master).publicKey.toBase58()
3756
3925
  };
3757
3926
  } finally {
@@ -5784,6 +5953,22 @@ function DecaneKit({ config, children }) {
5784
5953
  if (!sdk) throw new Error("Social wallet not connected");
5785
5954
  return sdk.getBalance(chain);
5786
5955
  }, []);
5956
+ const socialGetEthereumProvider = useCallback3((opts) => {
5957
+ const sdk = socialRef.current;
5958
+ if (!sdk) throw new Error("Social wallet not connected");
5959
+ return sdk.getEthereumProvider(opts);
5960
+ }, []);
5961
+ const socialSignAuthorization = useCallback3(
5962
+ async (req) => {
5963
+ const sdk = socialRef.current;
5964
+ if (!sdk) throw new Error("Social wallet not connected");
5965
+ return sdk.signAuthorization(req);
5966
+ },
5967
+ []
5968
+ );
5969
+ const socialGetAccessToken = useCallback3(() => {
5970
+ return socialRef.current?.getAccessToken() ?? null;
5971
+ }, []);
5787
5972
  const socialGetBalances = useCallback3(async () => {
5788
5973
  const sdk = socialRef.current;
5789
5974
  if (!sdk) throw new Error("Social wallet not connected");
@@ -5846,6 +6031,9 @@ function DecaneKit({ config, children }) {
5846
6031
  socialSendTransaction,
5847
6032
  socialGetBalance,
5848
6033
  socialGetBalances,
6034
+ socialGetEthereumProvider,
6035
+ socialSignAuthorization,
6036
+ socialGetAccessToken,
5849
6037
  socialSignSolanaTransaction,
5850
6038
  socialSignTypedData,
5851
6039
  socialRotateShares,
@@ -5918,7 +6106,7 @@ function useDecaneContext() {
5918
6106
  }
5919
6107
 
5920
6108
  // src/ui/hooks.ts
5921
- import { useState as useState4, useEffect as useEffect5, useCallback as useCallback4 } from "react";
6109
+ import { useState as useState4, useEffect as useEffect5, useCallback as useCallback4, useMemo } from "react";
5922
6110
  function useSocialAuth() {
5923
6111
  const {
5924
6112
  socialAuth,
@@ -6068,6 +6256,9 @@ function useSocialWallet() {
6068
6256
  socialSignTypedData,
6069
6257
  socialGetBalance,
6070
6258
  socialGetBalances,
6259
+ socialGetEthereumProvider,
6260
+ socialSignAuthorization,
6261
+ socialGetAccessToken,
6071
6262
  socialRotateShares,
6072
6263
  socialExportPortableBackup,
6073
6264
  socialHasRecoveryShare,
@@ -6112,6 +6303,10 @@ function useSocialWallet() {
6112
6303
  (chain) => run(() => socialGetBalance(chain)),
6113
6304
  [socialGetBalance]
6114
6305
  );
6306
+ const signAuthorization = useCallback4(
6307
+ (req) => run(() => socialSignAuthorization(req)),
6308
+ [socialSignAuthorization]
6309
+ );
6115
6310
  const getBalances = useCallback4(
6116
6311
  () => run(() => socialGetBalances()),
6117
6312
  [socialGetBalances]
@@ -6185,6 +6380,13 @@ function useSocialWallet() {
6185
6380
  // Balances (native token; read-only, works while locked)
6186
6381
  getBalance,
6187
6382
  getBalances,
6383
+ // EVM interop
6384
+ signAuthorization,
6385
+ // An EIP-1193 provider for viem/wagmi/ethers (memoized).
6386
+ getEthereumProvider: socialGetEthereumProvider,
6387
+ // The Decane JWT — authenticate the user to your own backend (bundler proxy,
6388
+ // etc.); verify server-side against backend.decane.app/.well-known/jwks.json.
6389
+ getAccessToken: socialGetAccessToken,
6188
6390
  // Recovery (2-of-3 Shamir share set)
6189
6391
  rotateShares,
6190
6392
  exportPortableBackup,
@@ -6242,6 +6444,18 @@ function useSocialBalance(chain) {
6242
6444
  }, [addrKey, chain]);
6243
6445
  return { balance, loading, error, refetch };
6244
6446
  }
6447
+ function useEthereumProvider(opts) {
6448
+ const { socialAuth, socialGetEthereumProvider } = useDecaneContext();
6449
+ const chainId = opts?.chainId;
6450
+ return useMemo(() => {
6451
+ if (!socialAuth.addresses?.evm) return null;
6452
+ try {
6453
+ return socialGetEthereumProvider(chainId ? { chainId } : void 0);
6454
+ } catch {
6455
+ return null;
6456
+ }
6457
+ }, [socialAuth.addresses?.evm, chainId]);
6458
+ }
6245
6459
  function toDecaneError(err) {
6246
6460
  if (err instanceof DecaneError) return err;
6247
6461
  const msg = err instanceof Error ? err.message : err?.message != null ? String(err.message) : String(err);
@@ -6498,9 +6712,11 @@ export {
6498
6712
  WrongPasswordError,
6499
6713
  createDecane,
6500
6714
  createDecaneConnect,
6715
+ createEthereumProvider,
6501
6716
  startEmailAuth,
6502
6717
  useChainSwitch,
6503
6718
  useDecane,
6719
+ useEthereumProvider,
6504
6720
  useSendTransaction,
6505
6721
  useSignMessage,
6506
6722
  useSignTypedData,