decane-connect-kit 2.2.8 → 2.3.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.d.cts CHANGED
@@ -294,6 +294,40 @@ 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 & {
320
+ signAuthorization?: (req: {
321
+ chainId: number;
322
+ address: string;
323
+ nonce: number;
324
+ }) => Promise<{
325
+ yParity: number;
326
+ r: string;
327
+ s: string;
328
+ }>;
329
+ }, opts?: EthereumProviderOptions): Eip1193Provider;
330
+
297
331
  type Chain = `evm:${number}` | `solana:${'mainnet' | 'devnet'}`;
298
332
  interface DecaneConnectConfig {
299
333
  /** Dashboard project ID (public). Sent with every request so the backend can
@@ -446,6 +480,30 @@ interface DecaneConnect {
446
480
  sendTransaction(req: SendTransactionRequest): Promise<string>;
447
481
  /** Sign EIP-712 typed data (EVM only). Throws on a Solana chain. */
448
482
  signTypedData(req: SignTypedDataRequest): Promise<string>;
483
+ /**
484
+ * A standard EIP-1193 Ethereum provider backed by this wallet — drop it into
485
+ * viem (`custom(provider)`), wagmi, or ethers (`BrowserProvider`). Signing
486
+ * goes through the TEE; reads are forwarded to the chain RPC. Memoized, so
487
+ * repeated calls return the same instance (safe for wagmi).
488
+ */
489
+ getEthereumProvider(opts?: {
490
+ chainId?: number;
491
+ }): Eip1193Provider;
492
+ /**
493
+ * Sign an EIP-7702 authorization, delegating this EOA to `address` on
494
+ * `chainId`. Enables account-abstraction / sponsored-gas flows: pair the
495
+ * returned {yParity, r, s} into a type-4 transaction's authorizationList.
496
+ * Requires a TEE signer that supports the 7702 path.
497
+ */
498
+ signAuthorization(req: {
499
+ chainId: number;
500
+ address: string;
501
+ nonce: number;
502
+ }): Promise<{
503
+ yParity: number;
504
+ r: string;
505
+ s: string;
506
+ }>;
449
507
  signSolanaTransaction(tx: Uint8Array): Promise<Uint8Array>;
450
508
  disconnect(): Promise<void>;
451
509
  getAddresses(): {
@@ -866,6 +924,18 @@ declare function useSocialWallet(): {
866
924
  chain: string;
867
925
  balance: BalanceResult | null;
868
926
  }[]>;
927
+ signAuthorization: (req: {
928
+ chainId: number;
929
+ address: string;
930
+ nonce: number;
931
+ }) => Promise<{
932
+ yParity: number;
933
+ r: string;
934
+ s: string;
935
+ }>;
936
+ getEthereumProvider: (opts?: {
937
+ chainId?: number;
938
+ }) => Eip1193Provider;
869
939
  rotateShares: (opts: {
870
940
  password: string;
871
941
  passwordHint?: string;
@@ -887,6 +957,9 @@ declare function useSocialBalance(chain?: string): {
887
957
  error: string | null;
888
958
  refetch: () => Promise<void>;
889
959
  };
960
+ declare function useEthereumProvider(opts?: {
961
+ chainId?: number;
962
+ }): Eip1193Provider | null;
890
963
  declare function useDecane(): {
891
964
  provider: DecaneProvider;
892
965
  wallets: UnifiedWalletAccount[];
@@ -959,4 +1032,4 @@ declare function useSignTypedData(): {
959
1032
  reset: () => void;
960
1033
  };
961
1034
 
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 };
1035
+ 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 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,40 @@ 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 & {
320
+ signAuthorization?: (req: {
321
+ chainId: number;
322
+ address: string;
323
+ nonce: number;
324
+ }) => Promise<{
325
+ yParity: number;
326
+ r: string;
327
+ s: string;
328
+ }>;
329
+ }, opts?: EthereumProviderOptions): Eip1193Provider;
330
+
297
331
  type Chain = `evm:${number}` | `solana:${'mainnet' | 'devnet'}`;
298
332
  interface DecaneConnectConfig {
299
333
  /** Dashboard project ID (public). Sent with every request so the backend can
@@ -446,6 +480,30 @@ interface DecaneConnect {
446
480
  sendTransaction(req: SendTransactionRequest): Promise<string>;
447
481
  /** Sign EIP-712 typed data (EVM only). Throws on a Solana chain. */
448
482
  signTypedData(req: SignTypedDataRequest): Promise<string>;
483
+ /**
484
+ * A standard EIP-1193 Ethereum provider backed by this wallet — drop it into
485
+ * viem (`custom(provider)`), wagmi, or ethers (`BrowserProvider`). Signing
486
+ * goes through the TEE; reads are forwarded to the chain RPC. Memoized, so
487
+ * repeated calls return the same instance (safe for wagmi).
488
+ */
489
+ getEthereumProvider(opts?: {
490
+ chainId?: number;
491
+ }): Eip1193Provider;
492
+ /**
493
+ * Sign an EIP-7702 authorization, delegating this EOA to `address` on
494
+ * `chainId`. Enables account-abstraction / sponsored-gas flows: pair the
495
+ * returned {yParity, r, s} into a type-4 transaction's authorizationList.
496
+ * Requires a TEE signer that supports the 7702 path.
497
+ */
498
+ signAuthorization(req: {
499
+ chainId: number;
500
+ address: string;
501
+ nonce: number;
502
+ }): Promise<{
503
+ yParity: number;
504
+ r: string;
505
+ s: string;
506
+ }>;
449
507
  signSolanaTransaction(tx: Uint8Array): Promise<Uint8Array>;
450
508
  disconnect(): Promise<void>;
451
509
  getAddresses(): {
@@ -866,6 +924,18 @@ declare function useSocialWallet(): {
866
924
  chain: string;
867
925
  balance: BalanceResult | null;
868
926
  }[]>;
927
+ signAuthorization: (req: {
928
+ chainId: number;
929
+ address: string;
930
+ nonce: number;
931
+ }) => Promise<{
932
+ yParity: number;
933
+ r: string;
934
+ s: string;
935
+ }>;
936
+ getEthereumProvider: (opts?: {
937
+ chainId?: number;
938
+ }) => Eip1193Provider;
869
939
  rotateShares: (opts: {
870
940
  password: string;
871
941
  passwordHint?: string;
@@ -887,6 +957,9 @@ declare function useSocialBalance(chain?: string): {
887
957
  error: string | null;
888
958
  refetch: () => Promise<void>;
889
959
  };
960
+ declare function useEthereumProvider(opts?: {
961
+ chainId?: number;
962
+ }): Eip1193Provider | null;
890
963
  declare function useDecane(): {
891
964
  provider: DecaneProvider;
892
965
  wallets: UnifiedWalletAccount[];
@@ -959,4 +1032,4 @@ declare function useSignTypedData(): {
959
1032
  reset: () => void;
960
1033
  };
961
1034
 
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 };
1035
+ 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 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 { 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,194 @@ 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
+ if (!client.signAuthorization) {
2879
+ throw Object.assign(new Error("EIP-7702 is not supported by the connected signer."), { code: 4200 });
2880
+ }
2881
+ const p = params[0];
2882
+ const cid = p.chainId != null ? Number(asBigInt(p.chainId)) : chainId;
2883
+ const address = p.address ?? p.contractAddress;
2884
+ const nonce = p.nonce != null ? Number(asBigInt(p.nonce)) : 0;
2885
+ return client.signAuthorization({ chainId: cid, address, nonce });
2886
+ }
2887
+ case "wallet_switchEthereumChain": {
2888
+ const p = params[0];
2889
+ chainId = Number(asBigInt(p.chainId));
2890
+ emit("chainChanged", toHex(chainId));
2891
+ return null;
2892
+ }
2893
+ case "wallet_addEthereumChain":
2894
+ return null;
2895
+ default:
2896
+ return rpc(args.method, params);
2897
+ }
2898
+ }
2899
+ const provider = {
2900
+ request,
2901
+ on(event, handler) {
2902
+ if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());
2903
+ listeners.get(event).add(handler);
2904
+ return this;
2905
+ },
2906
+ removeListener(event, handler) {
2907
+ listeners.get(event)?.delete(handler);
2908
+ return this;
2909
+ },
2910
+ isDecane: true
2911
+ };
2912
+ return provider;
2913
+ }
2914
+
2716
2915
  // src/social/signers/solana.ts
2717
2916
  import { VersionedTransaction as VTx } from "@solana/web3.js";
2718
2917
  function b64(bytes) {
@@ -2950,58 +3149,6 @@ async function buildPortableBackup(deviceShare, recoveryShare, password, address
2950
3149
  };
2951
3150
  }
2952
3151
 
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
3152
  // src/social/client.ts
3006
3153
  var DEFAULT_API_BASE = "https://backend.decane.app";
3007
3154
  var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
@@ -3074,6 +3221,7 @@ async function createDecaneConnect(config) {
3074
3221
  );
3075
3222
  let auth = null;
3076
3223
  let persisted = loadPersisted(PERSIST_KEY);
3224
+ let ethProvider = null;
3077
3225
  const persistSession = config.persistSession !== false;
3078
3226
  const SESSION_KEY = sessionPersistKey(config.apiKey);
3079
3227
  function persistLiveSession() {
@@ -3220,7 +3368,7 @@ async function createDecaneConnect(config) {
3220
3368
  let evmAddress;
3221
3369
  let solanaAddress;
3222
3370
  try {
3223
- evmAddress = new Wallet(toHex(master)).address;
3371
+ evmAddress = new Wallet(toHex2(master)).address;
3224
3372
  solanaAddress = Keypair.fromSeed(master).publicKey.toBase58();
3225
3373
  shareSet = await splitMaster(master, 1);
3226
3374
  } finally {
@@ -3581,6 +3729,21 @@ async function createDecaneConnect(config) {
3581
3729
  auth?.jwt
3582
3730
  );
3583
3731
  },
3732
+ async signAuthorization(req) {
3733
+ const tee = session.requireActive();
3734
+ return signEvmAuthorization(tee, req.chainId, req.address, req.nonce, auth?.jwt);
3735
+ },
3736
+ getEthereumProvider(opts) {
3737
+ if (!ethProvider) {
3738
+ const firstEvm = config.chains.find((c) => c.startsWith("evm:"));
3739
+ const defaultChainId = firstEvm ? parseInt(firstEvm.slice(4), 10) : 1;
3740
+ ethProvider = createEthereumProvider(client, {
3741
+ chainId: opts?.chainId ?? defaultChainId,
3742
+ rpcUrls: config.rpcUrls
3743
+ });
3744
+ }
3745
+ return ethProvider;
3746
+ },
3584
3747
  async signSolanaTransaction(serializedTx) {
3585
3748
  const tee = session.requireActive();
3586
3749
  let tx;
@@ -3744,14 +3907,14 @@ function b64uToBuffer(b64u) {
3744
3907
  const b644 = b64u.replace(/-/g, "+").replace(/_/g, "/");
3745
3908
  return Uint8Array.from(atob(b644), (c) => c.charCodeAt(0));
3746
3909
  }
3747
- function toHex(bytes) {
3910
+ function toHex2(bytes) {
3748
3911
  return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
3749
3912
  }
3750
3913
  async function deriveAddressesFromShares(a, b) {
3751
3914
  const master = await combineShares(a, b);
3752
3915
  try {
3753
3916
  return {
3754
- evm: new Wallet(toHex(master)).address,
3917
+ evm: new Wallet(toHex2(master)).address,
3755
3918
  solana: Keypair.fromSeed(master).publicKey.toBase58()
3756
3919
  };
3757
3920
  } finally {
@@ -5784,6 +5947,19 @@ function DecaneKit({ config, children }) {
5784
5947
  if (!sdk) throw new Error("Social wallet not connected");
5785
5948
  return sdk.getBalance(chain);
5786
5949
  }, []);
5950
+ const socialGetEthereumProvider = useCallback3((opts) => {
5951
+ const sdk = socialRef.current;
5952
+ if (!sdk) throw new Error("Social wallet not connected");
5953
+ return sdk.getEthereumProvider(opts);
5954
+ }, []);
5955
+ const socialSignAuthorization = useCallback3(
5956
+ async (req) => {
5957
+ const sdk = socialRef.current;
5958
+ if (!sdk) throw new Error("Social wallet not connected");
5959
+ return sdk.signAuthorization(req);
5960
+ },
5961
+ []
5962
+ );
5787
5963
  const socialGetBalances = useCallback3(async () => {
5788
5964
  const sdk = socialRef.current;
5789
5965
  if (!sdk) throw new Error("Social wallet not connected");
@@ -5846,6 +6022,8 @@ function DecaneKit({ config, children }) {
5846
6022
  socialSendTransaction,
5847
6023
  socialGetBalance,
5848
6024
  socialGetBalances,
6025
+ socialGetEthereumProvider,
6026
+ socialSignAuthorization,
5849
6027
  socialSignSolanaTransaction,
5850
6028
  socialSignTypedData,
5851
6029
  socialRotateShares,
@@ -5918,7 +6096,7 @@ function useDecaneContext() {
5918
6096
  }
5919
6097
 
5920
6098
  // src/ui/hooks.ts
5921
- import { useState as useState4, useEffect as useEffect5, useCallback as useCallback4 } from "react";
6099
+ import { useState as useState4, useEffect as useEffect5, useCallback as useCallback4, useMemo } from "react";
5922
6100
  function useSocialAuth() {
5923
6101
  const {
5924
6102
  socialAuth,
@@ -6068,6 +6246,8 @@ function useSocialWallet() {
6068
6246
  socialSignTypedData,
6069
6247
  socialGetBalance,
6070
6248
  socialGetBalances,
6249
+ socialGetEthereumProvider,
6250
+ socialSignAuthorization,
6071
6251
  socialRotateShares,
6072
6252
  socialExportPortableBackup,
6073
6253
  socialHasRecoveryShare,
@@ -6112,6 +6292,10 @@ function useSocialWallet() {
6112
6292
  (chain) => run(() => socialGetBalance(chain)),
6113
6293
  [socialGetBalance]
6114
6294
  );
6295
+ const signAuthorization = useCallback4(
6296
+ (req) => run(() => socialSignAuthorization(req)),
6297
+ [socialSignAuthorization]
6298
+ );
6115
6299
  const getBalances = useCallback4(
6116
6300
  () => run(() => socialGetBalances()),
6117
6301
  [socialGetBalances]
@@ -6185,6 +6369,10 @@ function useSocialWallet() {
6185
6369
  // Balances (native token; read-only, works while locked)
6186
6370
  getBalance,
6187
6371
  getBalances,
6372
+ // EVM interop
6373
+ signAuthorization,
6374
+ // An EIP-1193 provider for viem/wagmi/ethers (memoized).
6375
+ getEthereumProvider: socialGetEthereumProvider,
6188
6376
  // Recovery (2-of-3 Shamir share set)
6189
6377
  rotateShares,
6190
6378
  exportPortableBackup,
@@ -6242,6 +6430,18 @@ function useSocialBalance(chain) {
6242
6430
  }, [addrKey, chain]);
6243
6431
  return { balance, loading, error, refetch };
6244
6432
  }
6433
+ function useEthereumProvider(opts) {
6434
+ const { socialAuth, socialGetEthereumProvider } = useDecaneContext();
6435
+ const chainId = opts?.chainId;
6436
+ return useMemo(() => {
6437
+ if (!socialAuth.addresses?.evm) return null;
6438
+ try {
6439
+ return socialGetEthereumProvider(chainId ? { chainId } : void 0);
6440
+ } catch {
6441
+ return null;
6442
+ }
6443
+ }, [socialAuth.addresses?.evm, chainId]);
6444
+ }
6245
6445
  function toDecaneError(err) {
6246
6446
  if (err instanceof DecaneError) return err;
6247
6447
  const msg = err instanceof Error ? err.message : err?.message != null ? String(err.message) : String(err);
@@ -6498,9 +6698,11 @@ export {
6498
6698
  WrongPasswordError,
6499
6699
  createDecane,
6500
6700
  createDecaneConnect,
6701
+ createEthereumProvider,
6501
6702
  startEmailAuth,
6502
6703
  useChainSwitch,
6503
6704
  useDecane,
6705
+ useEthereumProvider,
6504
6706
  useSendTransaction,
6505
6707
  useSignMessage,
6506
6708
  useSignTypedData,