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.cjs CHANGED
@@ -207,9 +207,11 @@ __export(index_exports, {
207
207
  WrongPasswordError: () => WrongPasswordError,
208
208
  createDecane: () => createDecane,
209
209
  createDecaneConnect: () => createDecaneConnect,
210
+ createEthereumProvider: () => createEthereumProvider,
210
211
  startEmailAuth: () => startEmailAuth,
211
212
  useChainSwitch: () => useChainSwitch,
212
213
  useDecane: () => useDecane,
214
+ useEthereumProvider: () => useEthereumProvider,
213
215
  useSendTransaction: () => useSendTransaction,
214
216
  useSignMessage: () => useSignMessage,
215
217
  useSignTypedData: () => useSignTypedData,
@@ -2776,6 +2778,17 @@ async function signEvmTransaction(tee, chain, tx, jwt) {
2776
2778
  async function signEvmMessage(tee, chain, message, jwt) {
2777
2779
  return tee.sign({ chain, kind: "message", payload: message }, jwt);
2778
2780
  }
2781
+ async function signEvmAuthorization(tee, chainId, address, nonce, jwt) {
2782
+ const serialized = await tee.sign(
2783
+ { chain: `evm:${chainId}`, kind: "authorization", payload: JSON.stringify({ chainId, address, nonce }) },
2784
+ jwt
2785
+ );
2786
+ const hex = serialized.startsWith("0x") ? serialized.slice(2) : serialized;
2787
+ const r = "0x" + hex.slice(0, 64);
2788
+ const s = "0x" + hex.slice(64, 128);
2789
+ const v = parseInt(hex.slice(128, 130), 16);
2790
+ return { chainId, address, nonce, yParity: v >= 27 ? v - 27 : v, r, s };
2791
+ }
2779
2792
  async function signEvmTypedData(tee, chain, typedData, jwt) {
2780
2793
  const payload = JSON.stringify(
2781
2794
  typedData,
@@ -2784,6 +2797,191 @@ async function signEvmTypedData(tee, chain, typedData, jwt) {
2784
2797
  return tee.sign({ chain, kind: "typedData", payload }, jwt);
2785
2798
  }
2786
2799
 
2800
+ // src/social/balance.ts
2801
+ var DEFAULT_RPCS = {
2802
+ "evm:1": "https://ethereum.publicnode.com",
2803
+ "evm:137": "https://polygon.publicnode.com",
2804
+ "evm:8453": "https://base.publicnode.com",
2805
+ "evm:10": "https://optimism.publicnode.com",
2806
+ "evm:42161": "https://arbitrum-one.publicnode.com",
2807
+ "evm:56": "https://bsc.publicnode.com",
2808
+ "evm:11155111": "https://ethereum-sepolia.publicnode.com",
2809
+ "evm:84532": "https://base-sepolia.publicnode.com",
2810
+ "evm:31337": "http://localhost:8545"
2811
+ };
2812
+ var EVM_SYMBOLS = {
2813
+ "evm:137": "MATIC",
2814
+ "evm:56": "BNB"
2815
+ };
2816
+ function solanaEndpoint(chain, rpcUrls) {
2817
+ if (rpcUrls?.[chain]) return rpcUrls[chain];
2818
+ const cluster = chain.slice("solana:".length);
2819
+ return cluster === "devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com";
2820
+ }
2821
+ async function fetchBalance(opts) {
2822
+ const { kind, address, chain, rpcUrls } = opts;
2823
+ if (kind === "evm") {
2824
+ const rpcUrl = rpcUrls?.[chain] ?? DEFAULT_RPCS[chain];
2825
+ if (!rpcUrl) {
2826
+ throw new Error(
2827
+ `No RPC URL for ${chain}. Pass rpcUrls: { '${chain}': 'https://...' } in social config.`
2828
+ );
2829
+ }
2830
+ const { JsonRpcProvider, formatEther } = await import("ethers");
2831
+ const wei = await new JsonRpcProvider(rpcUrl).getBalance(address);
2832
+ return { raw: wei, formatted: formatEther(wei), symbol: EVM_SYMBOLS[chain] ?? "ETH", decimals: 18 };
2833
+ }
2834
+ const { Connection, PublicKey, LAMPORTS_PER_SOL } = await import("@solana/web3.js");
2835
+ const lamports = await new Connection(solanaEndpoint(chain, rpcUrls)).getBalance(
2836
+ new PublicKey(address)
2837
+ );
2838
+ return {
2839
+ raw: BigInt(lamports),
2840
+ formatted: String(lamports / LAMPORTS_PER_SOL),
2841
+ symbol: "SOL",
2842
+ decimals: 9
2843
+ };
2844
+ }
2845
+ function formatBalanceDisplay(value) {
2846
+ if (value == null) return "\u2014";
2847
+ const n = Number(value);
2848
+ if (!Number.isFinite(n)) return value;
2849
+ return n === 0 ? "0" : n < 1e-4 ? "<0.0001" : n.toFixed(4).replace(/\.?0+$/, "");
2850
+ }
2851
+
2852
+ // src/social/eip1193.ts
2853
+ function toHex(n) {
2854
+ return "0x" + n.toString(16);
2855
+ }
2856
+ function hexToBytes2(hex) {
2857
+ const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
2858
+ const bytes = new Uint8Array(clean.length / 2);
2859
+ for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(clean.substr(i * 2, 2), 16);
2860
+ return bytes;
2861
+ }
2862
+ function asBigInt(v) {
2863
+ if (v == null) return void 0;
2864
+ if (typeof v === "bigint") return v;
2865
+ if (typeof v === "number") return BigInt(v);
2866
+ if (typeof v === "string") return BigInt(v);
2867
+ return void 0;
2868
+ }
2869
+ function createEthereumProvider(client, opts = {}) {
2870
+ let chainId = opts.chainId ?? 1;
2871
+ const listeners = /* @__PURE__ */ new Map();
2872
+ function emit(event, ...args) {
2873
+ listeners.get(event)?.forEach((h) => {
2874
+ try {
2875
+ h(...args);
2876
+ } catch {
2877
+ }
2878
+ });
2879
+ }
2880
+ client.on("connected", () => {
2881
+ const evm = client.getAddresses()?.evm;
2882
+ emit("connect", { chainId: toHex(chainId) });
2883
+ if (evm) emit("accountsChanged", [evm]);
2884
+ });
2885
+ client.on("disconnected", () => {
2886
+ emit("accountsChanged", []);
2887
+ emit("disconnect", { code: 4900, message: "Wallet disconnected" });
2888
+ });
2889
+ const chainStr = () => `evm:${chainId}`;
2890
+ async function rpc(method, params) {
2891
+ const url = opts.rpcUrls?.[`evm:${chainId}`] ?? DEFAULT_RPCS[`evm:${chainId}`];
2892
+ if (!url) {
2893
+ throw Object.assign(new Error(`No RPC for chain ${chainId}. Pass rpcUrls.`), { code: 4900 });
2894
+ }
2895
+ let res;
2896
+ try {
2897
+ res = await fetch(url, {
2898
+ method: "POST",
2899
+ headers: { "Content-Type": "application/json" },
2900
+ body: JSON.stringify({ jsonrpc: "2.0", id: Date.now(), method, params })
2901
+ });
2902
+ } catch (e) {
2903
+ throw Object.assign(new Error(`RPC request failed: ${e.message}`), { code: 4900 });
2904
+ }
2905
+ const json = await res.json();
2906
+ if (json.error) throw Object.assign(new Error(json.error.message), { code: json.error.code });
2907
+ return json.result;
2908
+ }
2909
+ async function request(args) {
2910
+ const params = Array.isArray(args.params) ? args.params : args.params ? [args.params] : [];
2911
+ const addr = () => client.getAddresses()?.evm ?? null;
2912
+ switch (args.method) {
2913
+ case "eth_requestAccounts":
2914
+ case "eth_accounts": {
2915
+ const a = addr();
2916
+ return a ? [a] : [];
2917
+ }
2918
+ case "eth_chainId":
2919
+ return toHex(chainId);
2920
+ case "net_version":
2921
+ return String(chainId);
2922
+ case "personal_sign": {
2923
+ const message = params[0];
2924
+ const bytes = typeof message === "string" && message.startsWith("0x") ? hexToBytes2(message) : message;
2925
+ return client.signMessage({ chain: chainStr(), message: bytes });
2926
+ }
2927
+ case "eth_signTypedData_v4":
2928
+ case "eth_signTypedData": {
2929
+ const raw = params[1];
2930
+ const td = typeof raw === "string" ? JSON.parse(raw) : raw;
2931
+ return client.signTypedData({
2932
+ chain: chainStr(),
2933
+ domain: td.domain,
2934
+ types: td.types,
2935
+ message: td.message,
2936
+ primaryType: td.primaryType
2937
+ });
2938
+ }
2939
+ case "eth_sendTransaction": {
2940
+ const tx = params[0];
2941
+ return client.sendTransaction({
2942
+ chain: chainStr(),
2943
+ to: tx.to,
2944
+ value: asBigInt(tx.value),
2945
+ data: tx.data ?? tx.input,
2946
+ gasLimit: asBigInt(tx.gas ?? tx.gasLimit)
2947
+ });
2948
+ }
2949
+ case "eth_signAuthorization":
2950
+ case "wallet_sign7702Authorization": {
2951
+ const p = params[0];
2952
+ const cid = p.chainId != null ? Number(asBigInt(p.chainId)) : chainId;
2953
+ const address = p.address ?? p.contractAddress;
2954
+ const nonce = p.nonce != null ? Number(asBigInt(p.nonce)) : 0;
2955
+ return client.signAuthorization({ chainId: cid, address, nonce });
2956
+ }
2957
+ case "wallet_switchEthereumChain": {
2958
+ const p = params[0];
2959
+ chainId = Number(asBigInt(p.chainId));
2960
+ emit("chainChanged", toHex(chainId));
2961
+ return null;
2962
+ }
2963
+ case "wallet_addEthereumChain":
2964
+ return null;
2965
+ default:
2966
+ return rpc(args.method, params);
2967
+ }
2968
+ }
2969
+ const provider = {
2970
+ request,
2971
+ on(event, handler) {
2972
+ if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());
2973
+ listeners.get(event).add(handler);
2974
+ return this;
2975
+ },
2976
+ removeListener(event, handler) {
2977
+ listeners.get(event)?.delete(handler);
2978
+ return this;
2979
+ },
2980
+ isDecane: true
2981
+ };
2982
+ return provider;
2983
+ }
2984
+
2787
2985
  // src/social/signers/solana.ts
2788
2986
  var import_web3 = require("@solana/web3.js");
2789
2987
  function b64(bytes) {
@@ -3021,58 +3219,6 @@ async function buildPortableBackup(deviceShare, recoveryShare, password, address
3021
3219
  };
3022
3220
  }
3023
3221
 
3024
- // src/social/balance.ts
3025
- var DEFAULT_RPCS = {
3026
- "evm:1": "https://ethereum.publicnode.com",
3027
- "evm:137": "https://polygon.publicnode.com",
3028
- "evm:8453": "https://base.publicnode.com",
3029
- "evm:10": "https://optimism.publicnode.com",
3030
- "evm:42161": "https://arbitrum-one.publicnode.com",
3031
- "evm:56": "https://bsc.publicnode.com",
3032
- "evm:11155111": "https://ethereum-sepolia.publicnode.com",
3033
- "evm:84532": "https://base-sepolia.publicnode.com",
3034
- "evm:31337": "http://localhost:8545"
3035
- };
3036
- var EVM_SYMBOLS = {
3037
- "evm:137": "MATIC",
3038
- "evm:56": "BNB"
3039
- };
3040
- function solanaEndpoint(chain, rpcUrls) {
3041
- if (rpcUrls?.[chain]) return rpcUrls[chain];
3042
- const cluster = chain.slice("solana:".length);
3043
- return cluster === "devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com";
3044
- }
3045
- async function fetchBalance(opts) {
3046
- const { kind, address, chain, rpcUrls } = opts;
3047
- if (kind === "evm") {
3048
- const rpcUrl = rpcUrls?.[chain] ?? DEFAULT_RPCS[chain];
3049
- if (!rpcUrl) {
3050
- throw new Error(
3051
- `No RPC URL for ${chain}. Pass rpcUrls: { '${chain}': 'https://...' } in social config.`
3052
- );
3053
- }
3054
- const { JsonRpcProvider, formatEther } = await import("ethers");
3055
- const wei = await new JsonRpcProvider(rpcUrl).getBalance(address);
3056
- return { raw: wei, formatted: formatEther(wei), symbol: EVM_SYMBOLS[chain] ?? "ETH", decimals: 18 };
3057
- }
3058
- const { Connection, PublicKey, LAMPORTS_PER_SOL } = await import("@solana/web3.js");
3059
- const lamports = await new Connection(solanaEndpoint(chain, rpcUrls)).getBalance(
3060
- new PublicKey(address)
3061
- );
3062
- return {
3063
- raw: BigInt(lamports),
3064
- formatted: String(lamports / LAMPORTS_PER_SOL),
3065
- symbol: "SOL",
3066
- decimals: 9
3067
- };
3068
- }
3069
- function formatBalanceDisplay(value) {
3070
- if (value == null) return "\u2014";
3071
- const n = Number(value);
3072
- if (!Number.isFinite(n)) return value;
3073
- return n === 0 ? "0" : n < 1e-4 ? "<0.0001" : n.toFixed(4).replace(/\.?0+$/, "");
3074
- }
3075
-
3076
3222
  // src/social/client.ts
3077
3223
  var DEFAULT_API_BASE = "https://backend.decane.app";
3078
3224
  var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
@@ -3145,6 +3291,7 @@ async function createDecaneConnect(config) {
3145
3291
  );
3146
3292
  let auth = null;
3147
3293
  let persisted = loadPersisted(PERSIST_KEY);
3294
+ let ethProvider = null;
3148
3295
  const persistSession = config.persistSession !== false;
3149
3296
  const SESSION_KEY = sessionPersistKey(config.apiKey);
3150
3297
  function persistLiveSession() {
@@ -3291,7 +3438,7 @@ async function createDecaneConnect(config) {
3291
3438
  let evmAddress;
3292
3439
  let solanaAddress;
3293
3440
  try {
3294
- evmAddress = new import_ethers2.Wallet(toHex(master)).address;
3441
+ evmAddress = new import_ethers2.Wallet(toHex2(master)).address;
3295
3442
  solanaAddress = import_web32.Keypair.fromSeed(master).publicKey.toBase58();
3296
3443
  shareSet = await splitMaster(master, 1);
3297
3444
  } finally {
@@ -3652,6 +3799,30 @@ async function createDecaneConnect(config) {
3652
3799
  auth?.jwt
3653
3800
  );
3654
3801
  },
3802
+ async signAuthorization(req) {
3803
+ const tee = session.requireActive();
3804
+ const delegate = req.address ?? req.contractAddress;
3805
+ if (!delegate) throw new CallSequenceError("signAuthorization requires `address` (the delegate contract).");
3806
+ return signEvmAuthorization(tee, req.chainId, delegate, req.nonce, auth?.jwt);
3807
+ },
3808
+ // The current session's access token (the Decane JWT), for authenticating
3809
+ // the user to your own backend — e.g. a sponsored-bundler proxy. Verify it
3810
+ // server-side against https://backend.decane.app/.well-known/jwks.json.
3811
+ // Null when there is no live session.
3812
+ getAccessToken() {
3813
+ return auth?.jwt ?? null;
3814
+ },
3815
+ getEthereumProvider(opts) {
3816
+ if (!ethProvider) {
3817
+ const firstEvm = config.chains.find((c) => c.startsWith("evm:"));
3818
+ const defaultChainId = firstEvm ? parseInt(firstEvm.slice(4), 10) : 1;
3819
+ ethProvider = createEthereumProvider(client, {
3820
+ chainId: opts?.chainId ?? defaultChainId,
3821
+ rpcUrls: config.rpcUrls
3822
+ });
3823
+ }
3824
+ return ethProvider;
3825
+ },
3655
3826
  async signSolanaTransaction(serializedTx) {
3656
3827
  const tee = session.requireActive();
3657
3828
  let tx;
@@ -3815,14 +3986,14 @@ function b64uToBuffer(b64u) {
3815
3986
  const b644 = b64u.replace(/-/g, "+").replace(/_/g, "/");
3816
3987
  return Uint8Array.from(atob(b644), (c) => c.charCodeAt(0));
3817
3988
  }
3818
- function toHex(bytes) {
3989
+ function toHex2(bytes) {
3819
3990
  return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
3820
3991
  }
3821
3992
  async function deriveAddressesFromShares(a, b) {
3822
3993
  const master = await combineShares(a, b);
3823
3994
  try {
3824
3995
  return {
3825
- evm: new import_ethers2.Wallet(toHex(master)).address,
3996
+ evm: new import_ethers2.Wallet(toHex2(master)).address,
3826
3997
  solana: import_web32.Keypair.fromSeed(master).publicKey.toBase58()
3827
3998
  };
3828
3999
  } finally {
@@ -5848,6 +6019,22 @@ function DecaneKit({ config, children }) {
5848
6019
  if (!sdk) throw new Error("Social wallet not connected");
5849
6020
  return sdk.getBalance(chain);
5850
6021
  }, []);
6022
+ const socialGetEthereumProvider = (0, import_react5.useCallback)((opts) => {
6023
+ const sdk = socialRef.current;
6024
+ if (!sdk) throw new Error("Social wallet not connected");
6025
+ return sdk.getEthereumProvider(opts);
6026
+ }, []);
6027
+ const socialSignAuthorization = (0, import_react5.useCallback)(
6028
+ async (req) => {
6029
+ const sdk = socialRef.current;
6030
+ if (!sdk) throw new Error("Social wallet not connected");
6031
+ return sdk.signAuthorization(req);
6032
+ },
6033
+ []
6034
+ );
6035
+ const socialGetAccessToken = (0, import_react5.useCallback)(() => {
6036
+ return socialRef.current?.getAccessToken() ?? null;
6037
+ }, []);
5851
6038
  const socialGetBalances = (0, import_react5.useCallback)(async () => {
5852
6039
  const sdk = socialRef.current;
5853
6040
  if (!sdk) throw new Error("Social wallet not connected");
@@ -5910,6 +6097,9 @@ function DecaneKit({ config, children }) {
5910
6097
  socialSendTransaction,
5911
6098
  socialGetBalance,
5912
6099
  socialGetBalances,
6100
+ socialGetEthereumProvider,
6101
+ socialSignAuthorization,
6102
+ socialGetAccessToken,
5913
6103
  socialSignSolanaTransaction,
5914
6104
  socialSignTypedData,
5915
6105
  socialRotateShares,
@@ -6132,6 +6322,9 @@ function useSocialWallet() {
6132
6322
  socialSignTypedData,
6133
6323
  socialGetBalance,
6134
6324
  socialGetBalances,
6325
+ socialGetEthereumProvider,
6326
+ socialSignAuthorization,
6327
+ socialGetAccessToken,
6135
6328
  socialRotateShares,
6136
6329
  socialExportPortableBackup,
6137
6330
  socialHasRecoveryShare,
@@ -6176,6 +6369,10 @@ function useSocialWallet() {
6176
6369
  (chain) => run(() => socialGetBalance(chain)),
6177
6370
  [socialGetBalance]
6178
6371
  );
6372
+ const signAuthorization = (0, import_react6.useCallback)(
6373
+ (req) => run(() => socialSignAuthorization(req)),
6374
+ [socialSignAuthorization]
6375
+ );
6179
6376
  const getBalances = (0, import_react6.useCallback)(
6180
6377
  () => run(() => socialGetBalances()),
6181
6378
  [socialGetBalances]
@@ -6249,6 +6446,13 @@ function useSocialWallet() {
6249
6446
  // Balances (native token; read-only, works while locked)
6250
6447
  getBalance,
6251
6448
  getBalances,
6449
+ // EVM interop
6450
+ signAuthorization,
6451
+ // An EIP-1193 provider for viem/wagmi/ethers (memoized).
6452
+ getEthereumProvider: socialGetEthereumProvider,
6453
+ // The Decane JWT — authenticate the user to your own backend (bundler proxy,
6454
+ // etc.); verify server-side against backend.decane.app/.well-known/jwks.json.
6455
+ getAccessToken: socialGetAccessToken,
6252
6456
  // Recovery (2-of-3 Shamir share set)
6253
6457
  rotateShares,
6254
6458
  exportPortableBackup,
@@ -6306,6 +6510,18 @@ function useSocialBalance(chain) {
6306
6510
  }, [addrKey, chain]);
6307
6511
  return { balance, loading, error, refetch };
6308
6512
  }
6513
+ function useEthereumProvider(opts) {
6514
+ const { socialAuth, socialGetEthereumProvider } = useDecaneContext();
6515
+ const chainId = opts?.chainId;
6516
+ return (0, import_react6.useMemo)(() => {
6517
+ if (!socialAuth.addresses?.evm) return null;
6518
+ try {
6519
+ return socialGetEthereumProvider(chainId ? { chainId } : void 0);
6520
+ } catch {
6521
+ return null;
6522
+ }
6523
+ }, [socialAuth.addresses?.evm, chainId]);
6524
+ }
6309
6525
  function toDecaneError(err) {
6310
6526
  if (err instanceof DecaneError) return err;
6311
6527
  const msg = err instanceof Error ? err.message : err?.message != null ? String(err.message) : String(err);
@@ -6563,9 +6779,11 @@ function useSignTypedData() {
6563
6779
  WrongPasswordError,
6564
6780
  createDecane,
6565
6781
  createDecaneConnect,
6782
+ createEthereumProvider,
6566
6783
  startEmailAuth,
6567
6784
  useChainSwitch,
6568
6785
  useDecane,
6786
+ useEthereumProvider,
6569
6787
  useSendTransaction,
6570
6788
  useSignMessage,
6571
6789
  useSignTypedData,