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.cjs +259 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -1
- package/dist/index.d.ts +74 -1
- package/dist/index.js +258 -56
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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(
|
|
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
|
|
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(
|
|
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,
|