@chipi-stack/chipi-react 14.15.0 → 14.16.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.
@@ -14,13 +14,39 @@ type CreateWalletInput = {
14
14
  /**
15
15
  * Hook for creating a new wallet.
16
16
  *
17
- * Supports dual-key wrapping: when `usePasskey: true` AND `encryptKey` (PIN) provided,
18
- * the private key is encrypted twice — once with the passkey-derived key (primary) and
19
- * once with the PIN (backup). If passkey fails later, PIN recovers the wallet.
17
+ * With `usePasskey: true` the hook creates a WebAuthn passkey and uses its PRF
18
+ * output, derived on the device, as the key that encrypts the private key. It
19
+ * stores the passkey's `credentialId` and `prfSupported` on the wallet so any
20
+ * device with the synced passkey can unlock it later with
21
+ * `getWalletEncryptKey(wallet.credentialId, { prfSupported: wallet.prfSupported })`.
22
+ * On a device without WebAuthn PRF it throws with `code: "PRF_UNSUPPORTED"`
23
+ * (the original `PrfUnsupportedError` is the `cause`) instead of creating a
24
+ * custodial wallet.
25
+ *
26
+ * - Passkey only (`usePasskey: true`, no `encryptKey`): `authMethod: "passkey"`.
27
+ * Recommended for self-custodial apps; the passkey's platform sync (iCloud
28
+ * Keychain, Google Password Manager) is the recovery path.
29
+ * - Passkey + PIN (`usePasskey: true` and `encryptKey`): `authMethod: "passkey+pin"`.
30
+ * The private key is encrypted twice, once with the passkey key (primary)
31
+ * and once with the PIN (backup). The backup is only as strong as the PIN,
32
+ * which can be brute-forced offline against the stored ciphertext.
33
+ * - PIN only (`encryptKey`, no `usePasskey`): `authMethod: "pin"`. Legacy.
34
+ *
35
+ * The passkey's user name (shown by the OS passkey picker) is `externalUserId`.
20
36
  *
21
37
  * @example
22
38
  * ```tsx
23
- * // Passkey + PIN (recommended)
39
+ * // Passkey only (recommended)
40
+ * await createWalletAsync({
41
+ * params: {
42
+ * externalUserId: userId,
43
+ * chain: Chain.STARKNET,
44
+ * usePasskey: true, // Creates the passkey; its PRF output encrypts the key
45
+ * },
46
+ * bearerToken,
47
+ * });
48
+ *
49
+ * // Passkey + PIN backup
24
50
  * await createWalletAsync({
25
51
  * params: {
26
52
  * encryptKey: pin, // PIN backup
@@ -31,7 +57,7 @@ type CreateWalletInput = {
31
57
  * bearerToken,
32
58
  * });
33
59
  *
34
- * // PIN only (backward compatible)
60
+ * // PIN only (legacy)
35
61
  * await createWalletAsync({
36
62
  * params: {
37
63
  * encryptKey: pin,
@@ -1871,19 +1897,52 @@ type ChipiApprovalRequest = {
1871
1897
  * `[session_pubkey, r, s, valid_until]`.
1872
1898
  */
1873
1899
  interface ChipiSessionPolicy {
1874
- /** Allowed (contractAddress, entrypoint) pairs the session may call. */
1900
+ /**
1901
+ * Allowed (contractAddress, entrypoint) pairs the session may call.
1902
+ *
1903
+ * Client side, `useChipiWalletObject` only routes a call through the session
1904
+ * when its exact (contract, entrypoint) pair is listed. On-chain, though, the
1905
+ * session whitelist is per entrypoint selector only: allowing `transfer` lets
1906
+ * the session call `transfer` on ANY contract. Use `spendCaps` to bound what
1907
+ * the session can move per token.
1908
+ */
1875
1909
  allowedCalls: Array<{
1876
1910
  contractAddress: string;
1877
1911
  entrypoint: string;
1878
1912
  }>;
1879
1913
  /** Unix seconds after which the session is invalid. */
1880
1914
  validUntil: number;
1881
- /** Optional per-token spend caps, by token address. */
1882
- spendCaps?: Array<{
1883
- token: string;
1884
- amount: string;
1885
- }>;
1915
+ /**
1916
+ * Optional per-token spend caps, registered on-chain as spending policies in
1917
+ * the same transaction as the session. A cap must never resolve to a window
1918
+ * limit of 0 (on-chain, 0 means unlimited); that is rejected.
1919
+ */
1920
+ spendCaps?: ChipiSessionSpendCap[];
1921
+ }
1922
+ /**
1923
+ * Simple per-token cap: `amount` (base units, decimal or hex string) is used as
1924
+ * both the per-call and the per-window limit, with a window equal to the
1925
+ * session lifetime.
1926
+ */
1927
+ interface ChipiSessionSpendCapAmount {
1928
+ /** ERC-20 token contract address. */
1929
+ token: string;
1930
+ /** Cap in token base units (e.g. "5000000" = 5 USDC). Must be > 0. */
1931
+ amount: string;
1932
+ }
1933
+ /** Full per-token spending policy (mirrors `SpendingPolicyConfig`). */
1934
+ interface ChipiSessionSpendCapPolicy {
1935
+ /** ERC-20 token contract address. */
1936
+ token: string;
1937
+ /** Max amount per single call, in token base units. */
1938
+ maxPerCall: string | bigint;
1939
+ /** Max cumulative amount within the rolling window, in base units. Must be > 0. */
1940
+ maxPerWindow: string | bigint;
1941
+ /** Rolling window duration in seconds (positive integer). */
1942
+ windowSeconds: number;
1886
1943
  }
1944
+ /** A per-token spend cap: the simple `{ token, amount }` form or a full policy. */
1945
+ type ChipiSessionSpendCap = ChipiSessionSpendCapAmount | ChipiSessionSpendCapPolicy;
1887
1946
  /**
1888
1947
  * Everything the framework-agnostic SWO needs, supplied by the host layer
1889
1948
  * (`@chipi-stack/react`'s `useChipiWalletObject`, the hosted web-wallet, etc.).
@@ -1913,7 +1972,11 @@ interface ChipiWindowObjectDeps {
1913
1972
  getDeploymentData: () => Promise<AccountDeploymentData>;
1914
1973
  /** Optional: establish a session from a dApp-proposed policy (approve once). */
1915
1974
  createSession?: (policy: ChipiSessionPolicy) => Promise<void>;
1916
- /** Host approval gate. Defaults to auto-approve (harness) when omitted. */
1975
+ /**
1976
+ * Host approval gate: render the prompt and resolve `true` to approve.
1977
+ * When omitted, every approval is denied (deny by default) and a single
1978
+ * `console.warn` explains that `requestApproval` must be provided.
1979
+ */
1917
1980
  requestApproval?: (req: ChipiApprovalRequest) => Promise<boolean>;
1918
1981
  }
1919
1982
 
@@ -1932,7 +1995,11 @@ interface UseChipiWalletObjectConfig {
1932
1995
  sessionPolicy?: ChipiSessionPolicy | null;
1933
1996
  /** Chain id felt; defaults to SN_MAIN. */
1934
1997
  chainId?: string;
1935
- /** Host approval gate (connect / execute / signTypedData / session). */
1998
+ /**
1999
+ * Host approval gate (connect / execute / signTypedData / session). When
2000
+ * omitted, every approval is denied and a single `console.warn` explains
2001
+ * that `requestApproval` must be provided.
2002
+ */
1936
2003
  requestApproval?: (req: ChipiApprovalRequest) => Promise<boolean>;
1937
2004
  }
1938
2005
  /**
@@ -1945,6 +2012,15 @@ interface UseChipiWalletObjectConfig {
1945
2012
  * `injectChipiWallet`. `createSession(policy)` establishes a session on-chain
1946
2013
  * from a dApp-proposed policy (the "approve once" flow); the host stores the
1947
2014
  * returned SessionKeyData and feeds it back via `config.session`.
2015
+ *
2016
+ * Note: `allowedCalls` is matched per (contract, entrypoint) only client-side,
2017
+ * for routing. On-chain the session whitelist is per entrypoint selector, not
2018
+ * per contract, so pass `spendCaps` to bound token spend; with caps, the
2019
+ * session and its spending policies are registered in one owner-signed
2020
+ * transaction (`sdk.sessions.setupSession`).
2021
+ *
2022
+ * Approvals are deny-by-default: without `config.requestApproval`, every
2023
+ * approval is denied and a single `console.warn` says so.
1948
2024
  */
1949
2025
  declare function useChipiWalletObject(config: UseChipiWalletObjectConfig): {
1950
2026
  deps: ChipiWindowObjectDeps;
@@ -2890,4 +2966,4 @@ declare function usePrivateBalance(input: PrivateBalanceInput): {
2890
2966
  refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<Record<string, bigint>, Error>>;
2891
2967
  };
2892
2968
 
2893
- export { usePrivateBalance as $, useCallAnyContract as A, useSignTypedData as B, type ChipiWindowObjectDeps as C, useChipiWalletObject as D, useRecordSendTransaction as E, useGetTokenBalance as F, useCreateSessionKey as G, useAddSessionKeyToContract as H, useRevokeSessionKey as I, useGetSessionData as J, useExecuteWithSession as K, useX402Payment as L, type UseX402PaymentConfig as M, type UseX402PaymentReturn as N, useShhhSigner as O, type UseShhhSignerReturn as P, useGuardianRecovery as Q, type RegisterSessionConfig as R, type SessionState as S, type UseGuardianRecoveryReturn as T, type UseChipiWalletObjectConfig as U, useThresholdSign as V, type UseThresholdSignReturn as W, type UseThresholdSignOptions as X, type ThresholdSignState as Y, useShield as Z, useUnshield as _, type ChipiApprovalRequest as a, derivePrivacyAccount as a0, netPrivateBalance as a1, type PrivacyConfig as a2, type PrivacyKeys as a3, type PrivacyStep as a4, type ShieldHookInput as a5, type PrivacyLedgerEvent as a6, type PrivateBalanceInput as a7, type ChipiSessionPolicy as b, useGetWallet as c, useChipiWallet as d, type UseChipiWalletConfig as e, type UseChipiWalletReturn as f, type ChipiWalletData as g, useChipiSession as h, type UseChipiSessionConfig as i, type UseChipiSessionReturn as j, type SessionWallet as k, useMigrateWalletToPasskey as l, useUpdateWalletEncryption as m, useMigrateWalletToShhh as n, useTransfer as o, type UseTransferConfig as p, useApprove as q, useGetTransactionList as r, useGetTransaction as s, useGetTransactionStatus as t, useCreateWallet as u, useSyncOnChainTransfers as v, usePurchaseSku as w, useGetSkuPurchase as x, useGetSkuList as y, useGetSku as z };
2969
+ export { type ThresholdSignState as $, useGetSkuPurchase as A, useGetSkuList as B, type ChipiWindowObjectDeps as C, useGetSku as D, useCallAnyContract as E, useSignTypedData as F, useChipiWalletObject as G, useRecordSendTransaction as H, useGetTokenBalance as I, useCreateSessionKey as J, useAddSessionKeyToContract as K, useRevokeSessionKey as L, useGetSessionData as M, useExecuteWithSession as N, useX402Payment as O, type UseX402PaymentConfig as P, type UseX402PaymentReturn as Q, type RegisterSessionConfig as R, type SessionState as S, useShhhSigner as T, type UseChipiWalletObjectConfig as U, type UseShhhSignerReturn as V, useGuardianRecovery as W, type UseGuardianRecoveryReturn as X, useThresholdSign as Y, type UseThresholdSignReturn as Z, type UseThresholdSignOptions as _, type ChipiApprovalRequest as a, useShield as a0, useUnshield as a1, usePrivateBalance as a2, derivePrivacyAccount as a3, netPrivateBalance as a4, type PrivacyConfig as a5, type PrivacyKeys as a6, type PrivacyStep as a7, type ShieldHookInput as a8, type PrivacyLedgerEvent as a9, type PrivateBalanceInput as aa, type ChipiSessionPolicy as b, type ChipiSessionSpendCap as c, type ChipiSessionSpendCapAmount as d, type ChipiSessionSpendCapPolicy as e, useGetWallet as f, useChipiWallet as g, type UseChipiWalletConfig as h, type UseChipiWalletReturn as i, type ChipiWalletData as j, useChipiSession as k, type UseChipiSessionConfig as l, type UseChipiSessionReturn as m, type SessionWallet as n, useMigrateWalletToPasskey as o, useUpdateWalletEncryption as p, useMigrateWalletToShhh as q, useTransfer as r, type UseTransferConfig as s, useApprove as t, useCreateWallet as u, useGetTransactionList as v, useGetTransaction as w, useGetTransactionStatus as x, useSyncOnChainTransfers as y, usePurchaseSku as z };
@@ -14,13 +14,39 @@ type CreateWalletInput = {
14
14
  /**
15
15
  * Hook for creating a new wallet.
16
16
  *
17
- * Supports dual-key wrapping: when `usePasskey: true` AND `encryptKey` (PIN) provided,
18
- * the private key is encrypted twice — once with the passkey-derived key (primary) and
19
- * once with the PIN (backup). If passkey fails later, PIN recovers the wallet.
17
+ * With `usePasskey: true` the hook creates a WebAuthn passkey and uses its PRF
18
+ * output, derived on the device, as the key that encrypts the private key. It
19
+ * stores the passkey's `credentialId` and `prfSupported` on the wallet so any
20
+ * device with the synced passkey can unlock it later with
21
+ * `getWalletEncryptKey(wallet.credentialId, { prfSupported: wallet.prfSupported })`.
22
+ * On a device without WebAuthn PRF it throws with `code: "PRF_UNSUPPORTED"`
23
+ * (the original `PrfUnsupportedError` is the `cause`) instead of creating a
24
+ * custodial wallet.
25
+ *
26
+ * - Passkey only (`usePasskey: true`, no `encryptKey`): `authMethod: "passkey"`.
27
+ * Recommended for self-custodial apps; the passkey's platform sync (iCloud
28
+ * Keychain, Google Password Manager) is the recovery path.
29
+ * - Passkey + PIN (`usePasskey: true` and `encryptKey`): `authMethod: "passkey+pin"`.
30
+ * The private key is encrypted twice, once with the passkey key (primary)
31
+ * and once with the PIN (backup). The backup is only as strong as the PIN,
32
+ * which can be brute-forced offline against the stored ciphertext.
33
+ * - PIN only (`encryptKey`, no `usePasskey`): `authMethod: "pin"`. Legacy.
34
+ *
35
+ * The passkey's user name (shown by the OS passkey picker) is `externalUserId`.
20
36
  *
21
37
  * @example
22
38
  * ```tsx
23
- * // Passkey + PIN (recommended)
39
+ * // Passkey only (recommended)
40
+ * await createWalletAsync({
41
+ * params: {
42
+ * externalUserId: userId,
43
+ * chain: Chain.STARKNET,
44
+ * usePasskey: true, // Creates the passkey; its PRF output encrypts the key
45
+ * },
46
+ * bearerToken,
47
+ * });
48
+ *
49
+ * // Passkey + PIN backup
24
50
  * await createWalletAsync({
25
51
  * params: {
26
52
  * encryptKey: pin, // PIN backup
@@ -31,7 +57,7 @@ type CreateWalletInput = {
31
57
  * bearerToken,
32
58
  * });
33
59
  *
34
- * // PIN only (backward compatible)
60
+ * // PIN only (legacy)
35
61
  * await createWalletAsync({
36
62
  * params: {
37
63
  * encryptKey: pin,
@@ -1871,19 +1897,52 @@ type ChipiApprovalRequest = {
1871
1897
  * `[session_pubkey, r, s, valid_until]`.
1872
1898
  */
1873
1899
  interface ChipiSessionPolicy {
1874
- /** Allowed (contractAddress, entrypoint) pairs the session may call. */
1900
+ /**
1901
+ * Allowed (contractAddress, entrypoint) pairs the session may call.
1902
+ *
1903
+ * Client side, `useChipiWalletObject` only routes a call through the session
1904
+ * when its exact (contract, entrypoint) pair is listed. On-chain, though, the
1905
+ * session whitelist is per entrypoint selector only: allowing `transfer` lets
1906
+ * the session call `transfer` on ANY contract. Use `spendCaps` to bound what
1907
+ * the session can move per token.
1908
+ */
1875
1909
  allowedCalls: Array<{
1876
1910
  contractAddress: string;
1877
1911
  entrypoint: string;
1878
1912
  }>;
1879
1913
  /** Unix seconds after which the session is invalid. */
1880
1914
  validUntil: number;
1881
- /** Optional per-token spend caps, by token address. */
1882
- spendCaps?: Array<{
1883
- token: string;
1884
- amount: string;
1885
- }>;
1915
+ /**
1916
+ * Optional per-token spend caps, registered on-chain as spending policies in
1917
+ * the same transaction as the session. A cap must never resolve to a window
1918
+ * limit of 0 (on-chain, 0 means unlimited); that is rejected.
1919
+ */
1920
+ spendCaps?: ChipiSessionSpendCap[];
1921
+ }
1922
+ /**
1923
+ * Simple per-token cap: `amount` (base units, decimal or hex string) is used as
1924
+ * both the per-call and the per-window limit, with a window equal to the
1925
+ * session lifetime.
1926
+ */
1927
+ interface ChipiSessionSpendCapAmount {
1928
+ /** ERC-20 token contract address. */
1929
+ token: string;
1930
+ /** Cap in token base units (e.g. "5000000" = 5 USDC). Must be > 0. */
1931
+ amount: string;
1932
+ }
1933
+ /** Full per-token spending policy (mirrors `SpendingPolicyConfig`). */
1934
+ interface ChipiSessionSpendCapPolicy {
1935
+ /** ERC-20 token contract address. */
1936
+ token: string;
1937
+ /** Max amount per single call, in token base units. */
1938
+ maxPerCall: string | bigint;
1939
+ /** Max cumulative amount within the rolling window, in base units. Must be > 0. */
1940
+ maxPerWindow: string | bigint;
1941
+ /** Rolling window duration in seconds (positive integer). */
1942
+ windowSeconds: number;
1886
1943
  }
1944
+ /** A per-token spend cap: the simple `{ token, amount }` form or a full policy. */
1945
+ type ChipiSessionSpendCap = ChipiSessionSpendCapAmount | ChipiSessionSpendCapPolicy;
1887
1946
  /**
1888
1947
  * Everything the framework-agnostic SWO needs, supplied by the host layer
1889
1948
  * (`@chipi-stack/react`'s `useChipiWalletObject`, the hosted web-wallet, etc.).
@@ -1913,7 +1972,11 @@ interface ChipiWindowObjectDeps {
1913
1972
  getDeploymentData: () => Promise<AccountDeploymentData>;
1914
1973
  /** Optional: establish a session from a dApp-proposed policy (approve once). */
1915
1974
  createSession?: (policy: ChipiSessionPolicy) => Promise<void>;
1916
- /** Host approval gate. Defaults to auto-approve (harness) when omitted. */
1975
+ /**
1976
+ * Host approval gate: render the prompt and resolve `true` to approve.
1977
+ * When omitted, every approval is denied (deny by default) and a single
1978
+ * `console.warn` explains that `requestApproval` must be provided.
1979
+ */
1917
1980
  requestApproval?: (req: ChipiApprovalRequest) => Promise<boolean>;
1918
1981
  }
1919
1982
 
@@ -1932,7 +1995,11 @@ interface UseChipiWalletObjectConfig {
1932
1995
  sessionPolicy?: ChipiSessionPolicy | null;
1933
1996
  /** Chain id felt; defaults to SN_MAIN. */
1934
1997
  chainId?: string;
1935
- /** Host approval gate (connect / execute / signTypedData / session). */
1998
+ /**
1999
+ * Host approval gate (connect / execute / signTypedData / session). When
2000
+ * omitted, every approval is denied and a single `console.warn` explains
2001
+ * that `requestApproval` must be provided.
2002
+ */
1936
2003
  requestApproval?: (req: ChipiApprovalRequest) => Promise<boolean>;
1937
2004
  }
1938
2005
  /**
@@ -1945,6 +2012,15 @@ interface UseChipiWalletObjectConfig {
1945
2012
  * `injectChipiWallet`. `createSession(policy)` establishes a session on-chain
1946
2013
  * from a dApp-proposed policy (the "approve once" flow); the host stores the
1947
2014
  * returned SessionKeyData and feeds it back via `config.session`.
2015
+ *
2016
+ * Note: `allowedCalls` is matched per (contract, entrypoint) only client-side,
2017
+ * for routing. On-chain the session whitelist is per entrypoint selector, not
2018
+ * per contract, so pass `spendCaps` to bound token spend; with caps, the
2019
+ * session and its spending policies are registered in one owner-signed
2020
+ * transaction (`sdk.sessions.setupSession`).
2021
+ *
2022
+ * Approvals are deny-by-default: without `config.requestApproval`, every
2023
+ * approval is denied and a single `console.warn` says so.
1948
2024
  */
1949
2025
  declare function useChipiWalletObject(config: UseChipiWalletObjectConfig): {
1950
2026
  deps: ChipiWindowObjectDeps;
@@ -2890,4 +2966,4 @@ declare function usePrivateBalance(input: PrivateBalanceInput): {
2890
2966
  refetch: (options?: _tanstack_react_query.RefetchOptions) => Promise<_tanstack_react_query.QueryObserverResult<Record<string, bigint>, Error>>;
2891
2967
  };
2892
2968
 
2893
- export { usePrivateBalance as $, useCallAnyContract as A, useSignTypedData as B, type ChipiWindowObjectDeps as C, useChipiWalletObject as D, useRecordSendTransaction as E, useGetTokenBalance as F, useCreateSessionKey as G, useAddSessionKeyToContract as H, useRevokeSessionKey as I, useGetSessionData as J, useExecuteWithSession as K, useX402Payment as L, type UseX402PaymentConfig as M, type UseX402PaymentReturn as N, useShhhSigner as O, type UseShhhSignerReturn as P, useGuardianRecovery as Q, type RegisterSessionConfig as R, type SessionState as S, type UseGuardianRecoveryReturn as T, type UseChipiWalletObjectConfig as U, useThresholdSign as V, type UseThresholdSignReturn as W, type UseThresholdSignOptions as X, type ThresholdSignState as Y, useShield as Z, useUnshield as _, type ChipiApprovalRequest as a, derivePrivacyAccount as a0, netPrivateBalance as a1, type PrivacyConfig as a2, type PrivacyKeys as a3, type PrivacyStep as a4, type ShieldHookInput as a5, type PrivacyLedgerEvent as a6, type PrivateBalanceInput as a7, type ChipiSessionPolicy as b, useGetWallet as c, useChipiWallet as d, type UseChipiWalletConfig as e, type UseChipiWalletReturn as f, type ChipiWalletData as g, useChipiSession as h, type UseChipiSessionConfig as i, type UseChipiSessionReturn as j, type SessionWallet as k, useMigrateWalletToPasskey as l, useUpdateWalletEncryption as m, useMigrateWalletToShhh as n, useTransfer as o, type UseTransferConfig as p, useApprove as q, useGetTransactionList as r, useGetTransaction as s, useGetTransactionStatus as t, useCreateWallet as u, useSyncOnChainTransfers as v, usePurchaseSku as w, useGetSkuPurchase as x, useGetSkuList as y, useGetSku as z };
2969
+ export { type ThresholdSignState as $, useGetSkuPurchase as A, useGetSkuList as B, type ChipiWindowObjectDeps as C, useGetSku as D, useCallAnyContract as E, useSignTypedData as F, useChipiWalletObject as G, useRecordSendTransaction as H, useGetTokenBalance as I, useCreateSessionKey as J, useAddSessionKeyToContract as K, useRevokeSessionKey as L, useGetSessionData as M, useExecuteWithSession as N, useX402Payment as O, type UseX402PaymentConfig as P, type UseX402PaymentReturn as Q, type RegisterSessionConfig as R, type SessionState as S, useShhhSigner as T, type UseChipiWalletObjectConfig as U, type UseShhhSignerReturn as V, useGuardianRecovery as W, type UseGuardianRecoveryReturn as X, useThresholdSign as Y, type UseThresholdSignReturn as Z, type UseThresholdSignOptions as _, type ChipiApprovalRequest as a, useShield as a0, useUnshield as a1, usePrivateBalance as a2, derivePrivacyAccount as a3, netPrivateBalance as a4, type PrivacyConfig as a5, type PrivacyKeys as a6, type PrivacyStep as a7, type ShieldHookInput as a8, type PrivacyLedgerEvent as a9, type PrivateBalanceInput as aa, type ChipiSessionPolicy as b, type ChipiSessionSpendCap as c, type ChipiSessionSpendCapAmount as d, type ChipiSessionSpendCapPolicy as e, useGetWallet as f, useChipiWallet as g, type UseChipiWalletConfig as h, type UseChipiWalletReturn as i, type ChipiWalletData as j, useChipiSession as k, type UseChipiSessionConfig as l, type UseChipiSessionReturn as m, type SessionWallet as n, useMigrateWalletToPasskey as o, useUpdateWalletEncryption as p, useMigrateWalletToShhh as q, useTransfer as r, type UseTransferConfig as s, useApprove as t, useCreateWallet as u, useGetTransactionList as v, useGetTransaction as w, useGetTransactionStatus as x, useSyncOnChainTransfers as y, usePurchaseSku as z };
package/dist/index.d.mts CHANGED
@@ -4,8 +4,8 @@ import { ChipiSDK, NewOwnerInput } from '@chipi-stack/backend';
4
4
  import { ChipiSDKConfig, WalletType } from '@chipi-stack/types';
5
5
  export * from '@chipi-stack/types';
6
6
  export { Chain, ChainToken } from '@chipi-stack/types';
7
- import { C as ChipiWindowObjectDeps, U as UseChipiWalletObjectConfig } from './index-B8OIdrOX.mjs';
8
- export { a as ChipiApprovalRequest, b as ChipiSessionPolicy, g as ChipiWalletData, a2 as PrivacyConfig, a3 as PrivacyKeys, a6 as PrivacyLedgerEvent, a4 as PrivacyStep, a7 as PrivateBalanceInput, R as RegisterSessionConfig, S as SessionState, k as SessionWallet, a5 as ShieldHookInput, Y as ThresholdSignState, i as UseChipiSessionConfig, j as UseChipiSessionReturn, e as UseChipiWalletConfig, f as UseChipiWalletReturn, T as UseGuardianRecoveryReturn, P as UseShhhSignerReturn, X as UseThresholdSignOptions, W as UseThresholdSignReturn, p as UseTransferConfig, M as UseX402PaymentConfig, N as UseX402PaymentReturn, a0 as derivePrivacyAccount, a1 as netPrivateBalance, H as useAddSessionKeyToContract, q as useApprove, A as useCallAnyContract, h as useChipiSession, d as useChipiWallet, D as useChipiWalletObject, G as useCreateSessionKey, u as useCreateWallet, K as useExecuteWithSession, J as useGetSessionData, z as useGetSku, y as useGetSkuList, x as useGetSkuPurchase, F as useGetTokenBalance, s as useGetTransaction, r as useGetTransactionList, t as useGetTransactionStatus, c as useGetWallet, Q as useGuardianRecovery, l as useMigrateWalletToPasskey, n as useMigrateWalletToShhh, $ as usePrivateBalance, w as usePurchaseSku, E as useRecordSendTransaction, I as useRevokeSessionKey, O as useShhhSigner, Z as useShield, B as useSignTypedData, v as useSyncOnChainTransfers, V as useThresholdSign, o as useTransfer, _ as useUnshield, m as useUpdateWalletEncryption, L as useX402Payment } from './index-B8OIdrOX.mjs';
7
+ import { C as ChipiWindowObjectDeps, U as UseChipiWalletObjectConfig } from './index-Dbqp9oNS.mjs';
8
+ export { a as ChipiApprovalRequest, b as ChipiSessionPolicy, c as ChipiSessionSpendCap, d as ChipiSessionSpendCapAmount, e as ChipiSessionSpendCapPolicy, j as ChipiWalletData, a5 as PrivacyConfig, a6 as PrivacyKeys, a9 as PrivacyLedgerEvent, a7 as PrivacyStep, aa as PrivateBalanceInput, R as RegisterSessionConfig, S as SessionState, n as SessionWallet, a8 as ShieldHookInput, $ as ThresholdSignState, l as UseChipiSessionConfig, m as UseChipiSessionReturn, h as UseChipiWalletConfig, i as UseChipiWalletReturn, X as UseGuardianRecoveryReturn, V as UseShhhSignerReturn, _ as UseThresholdSignOptions, Z as UseThresholdSignReturn, s as UseTransferConfig, P as UseX402PaymentConfig, Q as UseX402PaymentReturn, a3 as derivePrivacyAccount, a4 as netPrivateBalance, K as useAddSessionKeyToContract, t as useApprove, E as useCallAnyContract, k as useChipiSession, g as useChipiWallet, G as useChipiWalletObject, J as useCreateSessionKey, u as useCreateWallet, N as useExecuteWithSession, M as useGetSessionData, D as useGetSku, B as useGetSkuList, A as useGetSkuPurchase, I as useGetTokenBalance, w as useGetTransaction, v as useGetTransactionList, x as useGetTransactionStatus, f as useGetWallet, W as useGuardianRecovery, o as useMigrateWalletToPasskey, q as useMigrateWalletToShhh, a2 as usePrivateBalance, z as usePurchaseSku, H as useRecordSendTransaction, L as useRevokeSessionKey, T as useShhhSigner, a0 as useShield, F as useSignTypedData, y as useSyncOnChainTransfers, Y as useThresholdSign, r as useTransfer, a1 as useUnshield, p as useUpdateWalletEncryption, O as useX402Payment } from './index-Dbqp9oNS.mjs';
9
9
  import { StarknetWindowObject } from '@starknet-io/types-js';
10
10
  import '@tanstack/react-query';
11
11
  import 'starknet';
@@ -61,6 +61,19 @@ declare function walletSupportsSessions(wallet: {
61
61
  * `deps`, so the same object powers walletv2's in-app browser, the hosted
62
62
  * web-wallet connector, and WalletConnect transport identically.
63
63
  *
64
+ * Approvals are deny-by-default: every sensitive action goes through
65
+ * `deps.requestApproval`. When it is omitted, every approval is denied (and a
66
+ * single `console.warn` says so) instead of being auto-approved.
67
+ *
68
+ * Connection model (per window object, i.e. per injected dApp page):
69
+ * - `wallet_requestAccounts` asks for a `connect` approval once, even when the
70
+ * wallet is unlocked and has accounts. With `silent_mode: true` it never
71
+ * prompts: it returns the accounts if already approved, else `[]`.
72
+ * - `wallet_getPermissions` returns `[]` until that approval, `["accounts"]` after.
73
+ * - `wallet_signTypedData` rejects (INVALID_REQUEST_PAYLOAD, no prompt) when
74
+ * the typed data's `domain.chainId` is set and differs from `deps.chainId`.
75
+ * "SN_MAIN" and "0x534e5f4d41494e" are treated as the same chain.
76
+ *
64
77
  * Returns the wallet plus an `emit` controller so the host can fire
65
78
  * accountsChanged / networkChanged on connect, disconnect, or lock.
66
79
  */
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@ import { ChipiSDK, NewOwnerInput } from '@chipi-stack/backend';
4
4
  import { ChipiSDKConfig, WalletType } from '@chipi-stack/types';
5
5
  export * from '@chipi-stack/types';
6
6
  export { Chain, ChainToken } from '@chipi-stack/types';
7
- import { C as ChipiWindowObjectDeps, U as UseChipiWalletObjectConfig } from './index-B8OIdrOX.js';
8
- export { a as ChipiApprovalRequest, b as ChipiSessionPolicy, g as ChipiWalletData, a2 as PrivacyConfig, a3 as PrivacyKeys, a6 as PrivacyLedgerEvent, a4 as PrivacyStep, a7 as PrivateBalanceInput, R as RegisterSessionConfig, S as SessionState, k as SessionWallet, a5 as ShieldHookInput, Y as ThresholdSignState, i as UseChipiSessionConfig, j as UseChipiSessionReturn, e as UseChipiWalletConfig, f as UseChipiWalletReturn, T as UseGuardianRecoveryReturn, P as UseShhhSignerReturn, X as UseThresholdSignOptions, W as UseThresholdSignReturn, p as UseTransferConfig, M as UseX402PaymentConfig, N as UseX402PaymentReturn, a0 as derivePrivacyAccount, a1 as netPrivateBalance, H as useAddSessionKeyToContract, q as useApprove, A as useCallAnyContract, h as useChipiSession, d as useChipiWallet, D as useChipiWalletObject, G as useCreateSessionKey, u as useCreateWallet, K as useExecuteWithSession, J as useGetSessionData, z as useGetSku, y as useGetSkuList, x as useGetSkuPurchase, F as useGetTokenBalance, s as useGetTransaction, r as useGetTransactionList, t as useGetTransactionStatus, c as useGetWallet, Q as useGuardianRecovery, l as useMigrateWalletToPasskey, n as useMigrateWalletToShhh, $ as usePrivateBalance, w as usePurchaseSku, E as useRecordSendTransaction, I as useRevokeSessionKey, O as useShhhSigner, Z as useShield, B as useSignTypedData, v as useSyncOnChainTransfers, V as useThresholdSign, o as useTransfer, _ as useUnshield, m as useUpdateWalletEncryption, L as useX402Payment } from './index-B8OIdrOX.js';
7
+ import { C as ChipiWindowObjectDeps, U as UseChipiWalletObjectConfig } from './index-Dbqp9oNS.js';
8
+ export { a as ChipiApprovalRequest, b as ChipiSessionPolicy, c as ChipiSessionSpendCap, d as ChipiSessionSpendCapAmount, e as ChipiSessionSpendCapPolicy, j as ChipiWalletData, a5 as PrivacyConfig, a6 as PrivacyKeys, a9 as PrivacyLedgerEvent, a7 as PrivacyStep, aa as PrivateBalanceInput, R as RegisterSessionConfig, S as SessionState, n as SessionWallet, a8 as ShieldHookInput, $ as ThresholdSignState, l as UseChipiSessionConfig, m as UseChipiSessionReturn, h as UseChipiWalletConfig, i as UseChipiWalletReturn, X as UseGuardianRecoveryReturn, V as UseShhhSignerReturn, _ as UseThresholdSignOptions, Z as UseThresholdSignReturn, s as UseTransferConfig, P as UseX402PaymentConfig, Q as UseX402PaymentReturn, a3 as derivePrivacyAccount, a4 as netPrivateBalance, K as useAddSessionKeyToContract, t as useApprove, E as useCallAnyContract, k as useChipiSession, g as useChipiWallet, G as useChipiWalletObject, J as useCreateSessionKey, u as useCreateWallet, N as useExecuteWithSession, M as useGetSessionData, D as useGetSku, B as useGetSkuList, A as useGetSkuPurchase, I as useGetTokenBalance, w as useGetTransaction, v as useGetTransactionList, x as useGetTransactionStatus, f as useGetWallet, W as useGuardianRecovery, o as useMigrateWalletToPasskey, q as useMigrateWalletToShhh, a2 as usePrivateBalance, z as usePurchaseSku, H as useRecordSendTransaction, L as useRevokeSessionKey, T as useShhhSigner, a0 as useShield, F as useSignTypedData, y as useSyncOnChainTransfers, Y as useThresholdSign, r as useTransfer, a1 as useUnshield, p as useUpdateWalletEncryption, O as useX402Payment } from './index-Dbqp9oNS.js';
9
9
  import { StarknetWindowObject } from '@starknet-io/types-js';
10
10
  import '@tanstack/react-query';
11
11
  import 'starknet';
@@ -61,6 +61,19 @@ declare function walletSupportsSessions(wallet: {
61
61
  * `deps`, so the same object powers walletv2's in-app browser, the hosted
62
62
  * web-wallet connector, and WalletConnect transport identically.
63
63
  *
64
+ * Approvals are deny-by-default: every sensitive action goes through
65
+ * `deps.requestApproval`. When it is omitted, every approval is denied (and a
66
+ * single `console.warn` says so) instead of being auto-approved.
67
+ *
68
+ * Connection model (per window object, i.e. per injected dApp page):
69
+ * - `wallet_requestAccounts` asks for a `connect` approval once, even when the
70
+ * wallet is unlocked and has accounts. With `silent_mode: true` it never
71
+ * prompts: it returns the accounts if already approved, else `[]`.
72
+ * - `wallet_getPermissions` returns `[]` until that approval, `["accounts"]` after.
73
+ * - `wallet_signTypedData` rejects (INVALID_REQUEST_PAYLOAD, no prompt) when
74
+ * the typed data's `domain.chainId` is set and differs from `deps.chainId`.
75
+ * "SN_MAIN" and "0x534e5f4d41494e" are treated as the same chain.
76
+ *
64
77
  * Returns the wallet plus an `emit` controller so the host can fire
65
78
  * accountsChanged / networkChanged on connect, disconnect, or lock.
66
79
  */
package/dist/index.js CHANGED
@@ -20418,6 +20418,41 @@ function hexEq(a, b) {
20418
20418
  return a === b;
20419
20419
  }
20420
20420
  }
20421
+ function parseCapAmount(value, field, token) {
20422
+ try {
20423
+ const v = typeof value === "bigint" ? value : BigInt(String(value).trim());
20424
+ if (v < 0n) throw new Error("negative");
20425
+ return v;
20426
+ } catch {
20427
+ throw new Error(
20428
+ `session_spend_cap_invalid: ${field} for token ${token} must be a non-negative integer in base units (got "${String(value)}")`
20429
+ );
20430
+ }
20431
+ }
20432
+ function toSpendingPolicies(caps, lifetimeSeconds) {
20433
+ return caps.map((cap) => {
20434
+ const policy = "maxPerWindow" in cap ? {
20435
+ token: cap.token,
20436
+ maxPerCall: parseCapAmount(cap.maxPerCall, "maxPerCall", cap.token),
20437
+ maxPerWindow: parseCapAmount(cap.maxPerWindow, "maxPerWindow", cap.token),
20438
+ windowSeconds: cap.windowSeconds
20439
+ } : (() => {
20440
+ const amount = parseCapAmount(cap.amount, "amount", cap.token);
20441
+ return {
20442
+ token: cap.token,
20443
+ maxPerCall: amount,
20444
+ maxPerWindow: amount,
20445
+ windowSeconds: Math.max(1, lifetimeSeconds)
20446
+ };
20447
+ })();
20448
+ if (policy.maxPerWindow === 0n) {
20449
+ throw new Error(
20450
+ `session_spend_cap_zero: the cap for token ${cap.token} resolves to maxPerWindow = 0, which means unlimited on-chain. Use a positive cap.`
20451
+ );
20452
+ }
20453
+ return policy;
20454
+ });
20455
+ }
20421
20456
  function sessionCovers(policy, calls) {
20422
20457
  if (!policy?.allowedCalls?.length) return false;
20423
20458
  return calls.every(
@@ -20432,6 +20467,10 @@ function useChipiWalletObject(config3) {
20432
20467
  const { signTypedDataAsync } = useSignTypedData();
20433
20468
  const { createSessionKeyAsync } = useCreateSessionKey();
20434
20469
  const { addSessionKeyToContractAsync } = useAddSessionKeyToContract();
20470
+ const { chipiSDK } = useChipiContext();
20471
+ const sdk = React.useRef(chipiSDK);
20472
+ sdk.current = chipiSDK;
20473
+ const warnedMissingApproval = React.useRef(false);
20435
20474
  const cfg = React.useRef(config3);
20436
20475
  cfg.current = config3;
20437
20476
  const requireWallet = () => {
@@ -20444,28 +20483,33 @@ function useChipiWalletObject(config3) {
20444
20483
  if (policy.validUntil <= nowSec()) throw new Error("session_policy_expired");
20445
20484
  const c = cfg.current;
20446
20485
  const wallet = requireWallet();
20486
+ const lifetimeSeconds = Math.max(1, policy.validUntil - nowSec());
20487
+ const spendingPolicies = policy.spendCaps?.length ? toSpendingPolicies(policy.spendCaps, lifetimeSeconds) : [];
20447
20488
  const encryptKey = await c.getEncryptKey();
20448
20489
  const session = await createSessionKeyAsync({
20449
20490
  encryptKey,
20450
- durationSeconds: Math.max(1, policy.validUntil - nowSec())
20491
+ durationSeconds: lifetimeSeconds
20451
20492
  });
20452
20493
  const bearerToken = await c.getBearerToken();
20453
- await addSessionKeyToContractAsync({
20454
- params: {
20455
- encryptKey,
20456
- wallet,
20457
- sessionConfig: {
20458
- sessionPublicKey: session.publicKey,
20459
- validUntil: policy.validUntil,
20460
- maxCalls: 1e3,
20461
- // selectors; empty = all entrypoints allowed
20462
- allowedEntrypoints: policy.allowedCalls.map(
20463
- (a) => hash_exports.getSelectorFromName(a.entrypoint)
20464
- )
20465
- }
20466
- },
20467
- bearerToken
20468
- });
20494
+ const params = {
20495
+ encryptKey,
20496
+ wallet,
20497
+ sessionConfig: {
20498
+ sessionPublicKey: session.publicKey,
20499
+ validUntil: policy.validUntil,
20500
+ maxCalls: 1e3,
20501
+ // Selectors; empty = all entrypoints allowed. On-chain this is a
20502
+ // per-selector whitelist, NOT scoped to allowedCalls' contracts.
20503
+ allowedEntrypoints: policy.allowedCalls.map(
20504
+ (a) => hash_exports.getSelectorFromName(a.entrypoint)
20505
+ )
20506
+ }
20507
+ };
20508
+ if (spendingPolicies.length > 0) {
20509
+ await sdk.current.sessions.setupSession({ ...params, spendingPolicies }, bearerToken);
20510
+ } else {
20511
+ await addSessionKeyToContractAsync({ params, bearerToken });
20512
+ }
20469
20513
  return session;
20470
20514
  },
20471
20515
  [createSessionKeyAsync, addSessionKeyToContractAsync]
@@ -20510,7 +20554,17 @@ function useChipiWalletObject(config3) {
20510
20554
  createSession: async (policy) => {
20511
20555
  await createSession(policy);
20512
20556
  },
20513
- requestApproval: (req) => cfg.current.requestApproval?.(req) ?? Promise.resolve(true)
20557
+ requestApproval: (req) => {
20558
+ const gate = cfg.current.requestApproval;
20559
+ if (gate) return gate(req);
20560
+ if (!warnedMissingApproval.current) {
20561
+ warnedMissingApproval.current = true;
20562
+ console.warn(
20563
+ "[ChipiSDK:Connect] No `requestApproval` was provided to useChipiWalletObject, so every approval (connect, execute, signTypedData, session) is denied. Pass `requestApproval` to show the user an approval UI and resolve true/false."
20564
+ );
20565
+ }
20566
+ return Promise.resolve(false);
20567
+ }
20514
20568
  }),
20515
20569
  [callAnyContractAsync, executeWithSessionAsync, signTypedDataAsync, createSession]
20516
20570
  );
@@ -21190,10 +21244,33 @@ var USER_REFUSED_OP = 113;
21190
21244
  var INVALID_REQUEST_PAYLOAD = 114;
21191
21245
  var ACCOUNT_ALREADY_DEPLOYED = 115;
21192
21246
  var UNKNOWN_ERROR = 163;
21247
+ var MISSING_APPROVAL_WARNING = "[ChipiSDK:Connect] No `requestApproval` was provided, so every approval (connect, execute, signTypedData, session) is denied. Pass `requestApproval` to show the user an approval UI and resolve true/false.";
21248
+ function normalizeChainId(value) {
21249
+ try {
21250
+ if (typeof value === "bigint") return value;
21251
+ if (typeof value === "number") {
21252
+ return Number.isSafeInteger(value) && value >= 0 ? BigInt(value) : null;
21253
+ }
21254
+ if (typeof value !== "string" || value.length === 0) return null;
21255
+ if (/^0x[0-9a-f]+$/i.test(value) || /^[0-9]+$/.test(value)) return BigInt(value);
21256
+ return BigInt(shortString_exports.encodeShortString(value));
21257
+ } catch {
21258
+ return null;
21259
+ }
21260
+ }
21193
21261
  function createChipiWindowObject(deps) {
21194
21262
  const accountListeners = /* @__PURE__ */ new Set();
21195
21263
  const networkListeners = /* @__PURE__ */ new Set();
21196
- const approve = deps.requestApproval ?? (async () => true);
21264
+ let approved = false;
21265
+ let pendingConnect = null;
21266
+ let warnedMissingApproval = false;
21267
+ const approve = deps.requestApproval ?? (async () => {
21268
+ if (!warnedMissingApproval) {
21269
+ warnedMissingApproval = true;
21270
+ console.warn(MISSING_APPROVAL_WARNING);
21271
+ }
21272
+ return false;
21273
+ });
21197
21274
  async function requireApproval(req) {
21198
21275
  const ok = await approve(req);
21199
21276
  if (!ok) throw new RpcError2(USER_REFUSED_OP, "User refused the operation");
@@ -21201,19 +21278,27 @@ function createChipiWindowObject(deps) {
21201
21278
  const request = (async (call) => {
21202
21279
  switch (call.type) {
21203
21280
  case "wallet_requestAccounts": {
21204
- const accounts = await deps.getAccounts();
21205
- if (accounts.length === 0) {
21206
- await requireApproval({ type: "connect" });
21207
- return deps.getAccounts();
21281
+ if (call.params?.silent_mode) {
21282
+ return approved ? deps.getAccounts() : [];
21283
+ }
21284
+ if (approved) {
21285
+ const accounts = await deps.getAccounts();
21286
+ if (accounts.length > 0) return accounts;
21208
21287
  }
21209
- return accounts;
21288
+ if (!pendingConnect) {
21289
+ pendingConnect = requireApproval({ type: "connect" }).then(() => {
21290
+ approved = true;
21291
+ }).finally(() => {
21292
+ pendingConnect = null;
21293
+ });
21294
+ }
21295
+ await pendingConnect;
21296
+ return deps.getAccounts();
21210
21297
  }
21211
21298
  case "wallet_requestChainId":
21212
21299
  return deps.chainId;
21213
- case "wallet_getPermissions": {
21214
- const accounts = await deps.getAccounts();
21215
- return accounts.length > 0 ? ["accounts"] : [];
21216
- }
21300
+ case "wallet_getPermissions":
21301
+ return approved ? ["accounts"] : [];
21217
21302
  case "wallet_addInvokeTransaction": {
21218
21303
  const wireCalls = call.params?.calls ?? [];
21219
21304
  if (wireCalls.length === 0) {
@@ -21226,14 +21311,31 @@ function createChipiWindowObject(deps) {
21226
21311
  }
21227
21312
  case "wallet_signTypedData": {
21228
21313
  const typedData = call.params;
21314
+ const domainChainId = typedData?.domain?.chainId;
21315
+ if (domainChainId !== void 0 && domainChainId !== null) {
21316
+ const expected = normalizeChainId(deps.chainId);
21317
+ const actual = normalizeChainId(domainChainId);
21318
+ if (actual === null || expected === null || actual !== expected) {
21319
+ throw new RpcError2(
21320
+ INVALID_REQUEST_PAYLOAD,
21321
+ `wallet_signTypedData: domain.chainId ${String(domainChainId)} does not match the wallet chain ${deps.chainId}`
21322
+ );
21323
+ }
21324
+ }
21229
21325
  await requireApproval({ type: "signTypedData", typedData });
21230
21326
  return deps.signTypedData(typedData);
21231
21327
  }
21232
21328
  case "wallet_deploymentData":
21233
21329
  try {
21234
21330
  return await deps.getDeploymentData();
21235
- } catch {
21236
- throw new RpcError2(ACCOUNT_ALREADY_DEPLOYED, "Account already deployed");
21331
+ } catch (err2) {
21332
+ if (err2 instanceof Error && err2.message === "account_already_deployed") {
21333
+ throw new RpcError2(ACCOUNT_ALREADY_DEPLOYED, "Account already deployed");
21334
+ }
21335
+ throw new RpcError2(
21336
+ UNKNOWN_ERROR,
21337
+ err2 instanceof Error ? err2.message : "Could not read deployment data"
21338
+ );
21237
21339
  }
21238
21340
  case "wallet_supportedSpecs":
21239
21341
  return SUPPORTED_SPECS;