@hub3js/core 0.58.2-next.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.
Files changed (162) hide show
  1. package/CHANGELOG.md +375 -0
  2. package/dist/hub/store/mod.js +2 -0
  3. package/dist/hub/store/mod.js.map +7 -0
  4. package/dist/legacy/mod.js +2 -0
  5. package/dist/legacy/mod.js.map +7 -0
  6. package/dist/mod.js +2 -0
  7. package/dist/mod.js.map +7 -0
  8. package/dist/namespaces/common/mod.js +2 -0
  9. package/dist/namespaces/common/mod.js.map +7 -0
  10. package/dist/namespaces/cosmos/mod.js +2 -0
  11. package/dist/namespaces/cosmos/mod.js.map +7 -0
  12. package/dist/namespaces/evm/mod.js +2 -0
  13. package/dist/namespaces/evm/mod.js.map +7 -0
  14. package/dist/namespaces/solana/mod.js +2 -0
  15. package/dist/namespaces/solana/mod.js.map +7 -0
  16. package/dist/namespaces/starknet/mod.js +2 -0
  17. package/dist/namespaces/starknet/mod.js.map +7 -0
  18. package/dist/namespaces/sui/mod.js +2 -0
  19. package/dist/namespaces/sui/mod.js.map +7 -0
  20. package/dist/namespaces/tron/mod.js +2 -0
  21. package/dist/namespaces/tron/mod.js.map +7 -0
  22. package/dist/namespaces/utxo/mod.js +2 -0
  23. package/dist/namespaces/utxo/mod.js.map +7 -0
  24. package/dist/namespaces/xrpl/mod.js +2 -0
  25. package/dist/namespaces/xrpl/mod.js.map +7 -0
  26. package/dist/utils/mod.js +2 -0
  27. package/dist/utils/mod.js.map +7 -0
  28. package/legacy/package.json +8 -0
  29. package/namespaces/common/package.json +8 -0
  30. package/namespaces/cosmos/package.json +8 -0
  31. package/namespaces/evm/package.json +8 -0
  32. package/namespaces/solana/package.json +8 -0
  33. package/namespaces/starknet/package.json +8 -0
  34. package/namespaces/sui/package.json +8 -0
  35. package/namespaces/tron/package.json +8 -0
  36. package/namespaces/utxo/package.json +8 -0
  37. package/namespaces/xrpl/package.json +8 -0
  38. package/package.json +100 -0
  39. package/readme.md +4 -0
  40. package/src/builders/action.ts +86 -0
  41. package/src/builders/mod.ts +5 -0
  42. package/src/builders/namespace.ts +258 -0
  43. package/src/builders/provider.ts +61 -0
  44. package/src/builders/types.ts +26 -0
  45. package/src/hub/helpers.ts +11 -0
  46. package/src/hub/hub.ts +128 -0
  47. package/src/hub/mod.ts +18 -0
  48. package/src/hub/namespaces/errors.ts +11 -0
  49. package/src/hub/namespaces/mod.ts +10 -0
  50. package/src/hub/namespaces/namespace.test.ts +443 -0
  51. package/src/hub/namespaces/namespace.ts +470 -0
  52. package/src/hub/namespaces/types.ts +58 -0
  53. package/src/hub/provider/mod.ts +10 -0
  54. package/src/hub/provider/provider.test.ts +232 -0
  55. package/src/hub/provider/provider.ts +335 -0
  56. package/src/hub/provider/types.ts +54 -0
  57. package/src/hub/store/events.ts +89 -0
  58. package/src/hub/store/extend.ts +125 -0
  59. package/src/hub/store/hub.ts +18 -0
  60. package/src/hub/store/mod.ts +25 -0
  61. package/src/hub/store/namespaces.ts +177 -0
  62. package/src/hub/store/providers.ts +169 -0
  63. package/src/hub/store/selectors.ts +59 -0
  64. package/src/hub/store/store.test.ts +50 -0
  65. package/src/hub/store/store.ts +30 -0
  66. package/src/legacy/helpers.ts +75 -0
  67. package/src/legacy/mod.ts +44 -0
  68. package/src/legacy/persistor.ts +19 -0
  69. package/src/legacy/types.ts +303 -0
  70. package/src/legacy/utils.ts +20 -0
  71. package/src/legacy/wallet.ts +552 -0
  72. package/src/mod.ts +44 -0
  73. package/src/namespaces/common/actions.ts +12 -0
  74. package/src/namespaces/common/after.ts +8 -0
  75. package/src/namespaces/common/and.ts +42 -0
  76. package/src/namespaces/common/before.ts +9 -0
  77. package/src/namespaces/common/builders.ts +14 -0
  78. package/src/namespaces/common/helpers.ts +10 -0
  79. package/src/namespaces/common/hooks/changeAccountSubscriber.test.ts +173 -0
  80. package/src/namespaces/common/hooks/changeAccountSubscriber.ts +236 -0
  81. package/src/namespaces/common/mod.ts +23 -0
  82. package/src/namespaces/common/or.ts +17 -0
  83. package/src/namespaces/common/types.ts +27 -0
  84. package/src/namespaces/common/utils.ts +43 -0
  85. package/src/namespaces/cosmos/actions.ts +3 -0
  86. package/src/namespaces/cosmos/after.ts +3 -0
  87. package/src/namespaces/cosmos/and.ts +5 -0
  88. package/src/namespaces/cosmos/before.ts +3 -0
  89. package/src/namespaces/cosmos/builders.ts +15 -0
  90. package/src/namespaces/cosmos/constants.ts +1 -0
  91. package/src/namespaces/cosmos/mod.ts +15 -0
  92. package/src/namespaces/cosmos/types.ts +31 -0
  93. package/src/namespaces/cosmos/utils.ts +21 -0
  94. package/src/namespaces/evm/actions.ts +134 -0
  95. package/src/namespaces/evm/after.ts +3 -0
  96. package/src/namespaces/evm/and.ts +5 -0
  97. package/src/namespaces/evm/before.ts +3 -0
  98. package/src/namespaces/evm/builders.ts +52 -0
  99. package/src/namespaces/evm/constants.ts +2 -0
  100. package/src/namespaces/evm/eip1193.ts +1415 -0
  101. package/src/namespaces/evm/hooks.ts +43 -0
  102. package/src/namespaces/evm/mod.ts +10 -0
  103. package/src/namespaces/evm/types.ts +36 -0
  104. package/src/namespaces/evm/utils.ts +106 -0
  105. package/src/namespaces/solana/actions.ts +44 -0
  106. package/src/namespaces/solana/after.ts +3 -0
  107. package/src/namespaces/solana/and.ts +5 -0
  108. package/src/namespaces/solana/before.ts +3 -0
  109. package/src/namespaces/solana/builders.ts +40 -0
  110. package/src/namespaces/solana/constants.ts +2 -0
  111. package/src/namespaces/solana/hooks.ts +10 -0
  112. package/src/namespaces/solana/mod.ts +10 -0
  113. package/src/namespaces/solana/types.ts +25 -0
  114. package/src/namespaces/solana/utils.ts +36 -0
  115. package/src/namespaces/starknet/actions.ts +19 -0
  116. package/src/namespaces/starknet/after.ts +3 -0
  117. package/src/namespaces/starknet/and.ts +5 -0
  118. package/src/namespaces/starknet/before.ts +3 -0
  119. package/src/namespaces/starknet/builders.ts +18 -0
  120. package/src/namespaces/starknet/constants.ts +8 -0
  121. package/src/namespaces/starknet/mod.ts +9 -0
  122. package/src/namespaces/starknet/types.ts +18 -0
  123. package/src/namespaces/starknet/utils.ts +35 -0
  124. package/src/namespaces/sui/actions.ts +27 -0
  125. package/src/namespaces/sui/builders.ts +77 -0
  126. package/src/namespaces/sui/constants.ts +8 -0
  127. package/src/namespaces/sui/hooks.ts +10 -0
  128. package/src/namespaces/sui/mod.ts +8 -0
  129. package/src/namespaces/sui/types.ts +25 -0
  130. package/src/namespaces/sui/utils.ts +56 -0
  131. package/src/namespaces/tron/actions.ts +3 -0
  132. package/src/namespaces/tron/after.ts +3 -0
  133. package/src/namespaces/tron/and.ts +5 -0
  134. package/src/namespaces/tron/before.ts +3 -0
  135. package/src/namespaces/tron/builders.ts +15 -0
  136. package/src/namespaces/tron/constants.ts +8 -0
  137. package/src/namespaces/tron/mod.ts +8 -0
  138. package/src/namespaces/tron/types.ts +14 -0
  139. package/src/namespaces/tron/utils.ts +18 -0
  140. package/src/namespaces/utxo/actions.ts +3 -0
  141. package/src/namespaces/utxo/after.ts +3 -0
  142. package/src/namespaces/utxo/and.ts +5 -0
  143. package/src/namespaces/utxo/before.ts +3 -0
  144. package/src/namespaces/utxo/builders.ts +12 -0
  145. package/src/namespaces/utxo/constants.ts +2 -0
  146. package/src/namespaces/utxo/mod.ts +8 -0
  147. package/src/namespaces/utxo/types.ts +14 -0
  148. package/src/namespaces/utxo/utils.ts +18 -0
  149. package/src/namespaces/xrpl/builders.ts +14 -0
  150. package/src/namespaces/xrpl/constants.ts +7 -0
  151. package/src/namespaces/xrpl/mod.ts +5 -0
  152. package/src/namespaces/xrpl/types.ts +16 -0
  153. package/src/namespaces/xrpl/utils.ts +15 -0
  154. package/src/test-utils/fixtures.ts +13 -0
  155. package/src/types/accounts.ts +12 -0
  156. package/src/types/actions.ts +13 -0
  157. package/src/types/mod.ts +1 -0
  158. package/src/types/utils.ts +7 -0
  159. package/src/utils/mod.ts +8 -0
  160. package/src/utils/versions.test.ts +24 -0
  161. package/src/utils/versions.ts +64 -0
  162. package/store/package.json +8 -0
@@ -0,0 +1,43 @@
1
+ import type { EIP1193EventMap } from './eip1193.js';
2
+ import type { EvmActions, ProviderAPI } from './types.js';
3
+ import type { Subscriber, SubscriberCleanUp } from '../../mod.js';
4
+
5
+ import { builders } from './mod.js';
6
+
7
+ export function changeAccountSubscriber(
8
+ instance: () => ProviderAPI,
9
+ ): [Subscriber<EvmActions>, SubscriberCleanUp<EvmActions>] {
10
+ return builders.changeAccountSubscriber(instance).build();
11
+ }
12
+
13
+ export function changeChainSubscriber(
14
+ instance: () => ProviderAPI,
15
+ ): [Subscriber<EvmActions>, SubscriberCleanUp<EvmActions>] {
16
+ let eventCallback: EIP1193EventMap['chainChanged'];
17
+
18
+ return [
19
+ (context) => {
20
+ const evmInstance = instance();
21
+
22
+ if (!evmInstance) {
23
+ throw new Error(
24
+ 'Trying to subscribe to your EVM wallet, but seems its instance is not available.',
25
+ );
26
+ }
27
+
28
+ const [, setState] = context.state();
29
+
30
+ eventCallback = async (chainId: string) => {
31
+ setState('network', chainId);
32
+ };
33
+ evmInstance.on('chainChanged', eventCallback);
34
+ },
35
+ () => {
36
+ const evmInstance = instance();
37
+
38
+ if (eventCallback && evmInstance) {
39
+ evmInstance.removeListener('chainChanged', eventCallback);
40
+ }
41
+ },
42
+ ];
43
+ }
@@ -0,0 +1,10 @@
1
+ export * as actions from './actions.js';
2
+ export * as hooks from './hooks.js';
3
+ export * as after from './after.js';
4
+ export * as and from './and.js';
5
+ export * as before from './before.js';
6
+ export * as utils from './utils.js';
7
+ export * as builders from './builders.js';
8
+
9
+ export type { EvmActions, ProviderAPI, Chain, ChainId } from './types.js';
10
+ export { CAIP_NAMESPACE, CAIP_ETHEREUM_CHAIN_ID } from './constants.js';
@@ -0,0 +1,36 @@
1
+ import type { AddEthereumChainParameter, EIP1193Provider } from './eip1193.js';
2
+ import type { AccountsWithActiveChain } from '../../types/accounts.js';
3
+ import type {
4
+ AutoImplementedActionsByRecommended,
5
+ CommonActions,
6
+ } from '../common/types.js';
7
+ import type { BlockchainMeta } from 'rango-types';
8
+
9
+ export interface EvmActions
10
+ extends AutoImplementedActionsByRecommended, CommonActions {
11
+ connect: (
12
+ chain?: Chain | ChainId,
13
+ options?: ConnectOptions,
14
+ ) => Promise<AccountsWithActiveChain>;
15
+ canEagerConnect: () => Promise<boolean>;
16
+ canSwitchNetwork: (params: CanSwitchNetworkParams) => boolean;
17
+ getChainId: () => Promise<`0x${string}`>;
18
+ }
19
+ type CanSwitchNetworkParams = {
20
+ network: string;
21
+ supportedChains: BlockchainMeta[];
22
+ };
23
+
24
+ export type ProviderAPI = EIP1193Provider;
25
+ // A 0x-prefixed hexadecimal string
26
+ export type ChainId = string;
27
+ export type Chain = AddEthereumChainParameter;
28
+ export type ProviderAccounts = {
29
+ accounts: string[];
30
+ chainId: ChainId;
31
+ };
32
+ export type ConnectOptions = {
33
+ switchOrAddNetwork?: (instance: ProviderAPI, chain: ChainId | Chain) => void;
34
+ getAccounts?: (provider: ProviderAPI) => Promise<ProviderAccounts>;
35
+ derivationPath?: string;
36
+ };
@@ -0,0 +1,106 @@
1
+ import type { Chain, ChainId, ProviderAPI } from './types.js';
2
+ import type { CaipAccount } from '../../types/accounts.js';
3
+
4
+ import { AccountId } from 'caip';
5
+ import { type BlockchainMeta, evmBlockchains } from 'rango-types';
6
+
7
+ import { CAIP_NAMESPACE } from './constants.js';
8
+
9
+ const CHAIN_ID_RADIX = 16;
10
+
11
+ export async function getAccounts(provider: ProviderAPI) {
12
+ const [accounts, chainId] = await Promise.all([
13
+ provider.request({ method: 'eth_requestAccounts' }),
14
+ provider.request({ method: 'eth_chainId' }),
15
+ ]);
16
+ /*
17
+ * Trust Wallet Compatibility Fix:
18
+ * Trust Wallet's in-app browser has been observed to return the `chainId` as a
19
+ * number (e.g., 1) rather than the standard hexadecimal string (e.g., "0x1").
20
+ * This code block standardizes the `chainId` to the required hex format to
21
+ * prevent downstream errors.
22
+ */
23
+ let standardChainId = chainId;
24
+ if (typeof standardChainId === 'number') {
25
+ standardChainId = `0x${Number(chainId).toString(CHAIN_ID_RADIX)}`;
26
+ }
27
+
28
+ return {
29
+ accounts,
30
+ chainId: standardChainId,
31
+ };
32
+ }
33
+
34
+ export async function suggestNetwork(instance: ProviderAPI, chain: Chain) {
35
+ return await instance.request({
36
+ method: 'wallet_addEthereumChain',
37
+ params: [chain],
38
+ });
39
+ }
40
+
41
+ export async function switchNetwork(instance: ProviderAPI, chainId: ChainId) {
42
+ return await instance.request({
43
+ method: 'wallet_switchEthereumChain',
44
+ params: [{ chainId: chainId }],
45
+ });
46
+ }
47
+ export function filterAndGetEvmBlockchainNames(meta: BlockchainMeta[]) {
48
+ return evmBlockchains(meta).map((blockchain) => blockchain.name);
49
+ }
50
+ export async function switchOrAddNetwork(
51
+ instance: ProviderAPI,
52
+ chain: ChainId | Chain,
53
+ ) {
54
+ try {
55
+ const chainId = typeof chain === 'string' ? chain : chain.chainId;
56
+ await switchNetwork(instance, chainId);
57
+ } catch (switchError) {
58
+ const error = switchError as { code: number };
59
+
60
+ /*
61
+ * Error code 4902 is used by MetaMask to indicate that the requested chain has not been added to the wallet.
62
+ * This code is not part of the official EIP-1193 spec (https://eips.ethereum.org/EIPS/eip-1193#supported-rpc-methods),
63
+ * so other providers may use a different code or behavior for the same condition.
64
+ */
65
+ const NOT_FOUND_CHAIN_ERROR_CODE = 4902;
66
+ if (
67
+ typeof chain !== 'string' &&
68
+ (error.code === NOT_FOUND_CHAIN_ERROR_CODE || !error.code)
69
+ ) {
70
+ /*
71
+ * Note: on WalletConnect `code` is undefined so we have to use !switchError.code as fallback.
72
+ * This error code indicates that the chain has not been added to wallet.
73
+ */
74
+ await suggestNetwork(instance, chain);
75
+ return;
76
+ }
77
+ throw switchError;
78
+ }
79
+ }
80
+
81
+ const EIP_1193_USER_REJECTION_ERROR_CODE = 4001;
82
+ export function isUserRejectionError(error: unknown): boolean {
83
+ // EIP-1193 user rejection error can be in error.code or error.cause.code
84
+ if (typeof error === 'object' && error !== null) {
85
+ const code = (error as { code?: number }).code;
86
+ const causeCode = (error as { cause?: { code?: number } }).cause?.code;
87
+ return (
88
+ code === EIP_1193_USER_REJECTION_ERROR_CODE ||
89
+ causeCode === EIP_1193_USER_REJECTION_ERROR_CODE
90
+ );
91
+ }
92
+ return false;
93
+ }
94
+
95
+ export function formatAccountsToCAIP(accounts: string[], chainId: string) {
96
+ return accounts.map(
97
+ (account) =>
98
+ AccountId.format({
99
+ address: account,
100
+ chainId: {
101
+ namespace: CAIP_NAMESPACE,
102
+ reference: chainId,
103
+ },
104
+ }) as CaipAccount,
105
+ );
106
+ }
@@ -0,0 +1,44 @@
1
+ import type { ProviderAPI, SolanaActions } from './types.js';
2
+ import type { Context } from '../../hub/namespaces/mod.js';
3
+ import type { FunctionWithContext } from '../../types/actions.js';
4
+
5
+ import { recommended as commonRecommended } from '../common/actions.js';
6
+
7
+ import { formatAccountsToCAIP, getAccounts } from './utils.js';
8
+
9
+ export const recommended = [...commonRecommended];
10
+
11
+ export function connect(
12
+ instance: () => ProviderAPI,
13
+ ): FunctionWithContext<SolanaActions['connect'], Context> {
14
+ return async () => {
15
+ const solanaInstance = instance();
16
+ const result = await getAccounts(solanaInstance);
17
+
18
+ if (Array.isArray(result)) {
19
+ throw new Error(
20
+ 'Expecting solana response to be a single value, not an array.',
21
+ );
22
+ }
23
+
24
+ return formatAccountsToCAIP(result.accounts);
25
+ };
26
+ }
27
+ export function canEagerConnect(instance: () => ProviderAPI) {
28
+ return async () => {
29
+ const solanaInstance = instance();
30
+
31
+ if (!solanaInstance) {
32
+ throw new Error(
33
+ 'Trying to eagerly connect to your Solana wallet, but seems its instance is not available.',
34
+ );
35
+ }
36
+
37
+ try {
38
+ const result = await solanaInstance.connect({ onlyIfTrusted: true });
39
+ return !!result;
40
+ } catch {
41
+ return false;
42
+ }
43
+ };
44
+ }
@@ -0,0 +1,3 @@
1
+ import { recommended as commonRecommended } from '../common/after.js';
2
+
3
+ export const recommended = [...commonRecommended];
@@ -0,0 +1,5 @@
1
+ import { connectAndUpdateStateForSingleNetwork } from '../common/mod.js';
2
+
3
+ export const recommended = [
4
+ ['connect', connectAndUpdateStateForSingleNetwork] as const,
5
+ ];
@@ -0,0 +1,3 @@
1
+ import { recommended as commonRecommended } from '../common/before.js';
2
+
3
+ export const recommended = [...commonRecommended];
@@ -0,0 +1,40 @@
1
+ import type { ProviderAPI, SolanaActions } from './types.js';
2
+
3
+ import { ActionBuilder } from '../../mod.js';
4
+ import { ChangeAccountSubscriberBuilder } from '../common/hooks/changeAccountSubscriber.js';
5
+ import {
6
+ connectAndUpdateStateForSingleNetwork,
7
+ intoConnecting,
8
+ intoConnectionFinished,
9
+ } from '../common/mod.js';
10
+
11
+ import { formatAccountsToCAIP } from './utils.js';
12
+
13
+ // Actions
14
+ export const connect = () =>
15
+ new ActionBuilder<SolanaActions, 'connect'>('connect')
16
+ .and(connectAndUpdateStateForSingleNetwork)
17
+ .before(intoConnecting)
18
+ .after(intoConnectionFinished);
19
+
20
+ // Hooks
21
+ export const changeAccountSubscriber = (getInstance: () => ProviderAPI) =>
22
+ new ChangeAccountSubscriberBuilder<string, ProviderAPI, SolanaActions>()
23
+ .getInstance(getInstance)
24
+ /*
25
+ * In some wallets, when a user switches to an account not yet connected to the dApp, it returns null.
26
+ * A null value indicates no access to the account, requiring a disconnect and user reconnection.
27
+ */
28
+ .onSwitchAccount((event, context) => {
29
+ if (!event.payload) {
30
+ context.action('disconnect');
31
+ event.preventDefault();
32
+ }
33
+ })
34
+ .format(async (_, accounts) => formatAccountsToCAIP([accounts]))
35
+ .addEventListener((instance, callback) => {
36
+ instance.on('accountChanged', callback);
37
+ })
38
+ .removeEventListener((instance, callback) => {
39
+ instance.off('accountChanged', callback);
40
+ });
@@ -0,0 +1,2 @@
1
+ export const CAIP_NAMESPACE = 'solana';
2
+ export const CAIP_SOLANA_CHAIN_ID = '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';
@@ -0,0 +1,10 @@
1
+ import type { ProviderAPI, SolanaActions } from './types.js';
2
+ import type { Subscriber, SubscriberCleanUp } from '../../mod.js';
3
+
4
+ import { builders } from './mod.js';
5
+
6
+ export function changeAccountSubscriber(
7
+ instance: () => ProviderAPI,
8
+ ): [Subscriber<SolanaActions>, SubscriberCleanUp<SolanaActions>] {
9
+ return builders.changeAccountSubscriber(instance).build();
10
+ }
@@ -0,0 +1,10 @@
1
+ export * as actions from './actions.js';
2
+ export * as hooks from './hooks.js';
3
+ export * as after from './after.js';
4
+ export * as and from './and.js';
5
+ export * as before from './before.js';
6
+ export * as builders from './builders.js';
7
+ export * as utils from './utils.js';
8
+
9
+ export type { ProviderAPI, SolanaActions } from './types.js';
10
+ export { CAIP_NAMESPACE, CAIP_SOLANA_CHAIN_ID } from './constants.js';
@@ -0,0 +1,25 @@
1
+ import type { Accounts } from '../../types/accounts.js';
2
+ import type {
3
+ AutoImplementedActionsByRecommended,
4
+ CommonActions,
5
+ } from '../common/types.js';
6
+
7
+ export interface SolanaActions
8
+ extends AutoImplementedActionsByRecommended, CommonActions {
9
+ connect: (options?: ConnectOptions) => Promise<Accounts>;
10
+ canEagerConnect: () => Promise<boolean>;
11
+ }
12
+
13
+ /*
14
+ *
15
+ * TODO: That would be better to define a type for Solana injected wallets.
16
+ * They have something called [Wallet Standard](https://github.com/wallet-standard/wallet-standard) but not sure all the Solana wallets support that (Phantom do).
17
+ * If Phantom's interface is what Solana wallets are supporting, another option would be define that type here.
18
+ *
19
+ */
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
+ export type ProviderAPI = Record<string, any>;
22
+
23
+ export type ConnectOptions = {
24
+ derivationPath?: string;
25
+ };
@@ -0,0 +1,36 @@
1
+ import type { ProviderAPI } from './types.js';
2
+ import type { CaipAccount } from '../../types/accounts.js';
3
+
4
+ import { AccountId } from 'caip';
5
+
6
+ import { LegacyNetworks } from '../../legacy/mod.js';
7
+
8
+ import { CAIP_NAMESPACE, CAIP_SOLANA_CHAIN_ID } from './constants.js';
9
+
10
+ export async function getAccounts(provider: ProviderAPI) {
11
+ const solanaResponse = await provider.connect();
12
+ /*
13
+ * Fallback for wallets like Coinbase that return no response on connect.
14
+ * If solanaResponse is undefined, use the provider's publicKey directly.
15
+ */
16
+ const account = solanaResponse
17
+ ? solanaResponse.publicKey.toString()
18
+ : provider.publicKey.toString();
19
+ return {
20
+ accounts: [account],
21
+ chainId: LegacyNetworks.SOLANA,
22
+ };
23
+ }
24
+
25
+ export function formatAccountsToCAIP(accounts: string[]) {
26
+ return accounts.map(
27
+ (account) =>
28
+ AccountId.format({
29
+ address: account.toString(),
30
+ chainId: {
31
+ namespace: CAIP_NAMESPACE,
32
+ reference: CAIP_SOLANA_CHAIN_ID,
33
+ },
34
+ }) as CaipAccount,
35
+ );
36
+ }
@@ -0,0 +1,19 @@
1
+ import type { ProviderAPI } from './types.js';
2
+
3
+ import { recommended as commonRecommended } from '../common/actions.js';
4
+
5
+ export const recommended = [...commonRecommended];
6
+
7
+ export function canEagerConnect(instance: () => ProviderAPI) {
8
+ return async () => {
9
+ const starknetInstance = instance();
10
+
11
+ if (!starknetInstance) {
12
+ throw new Error(
13
+ 'Trying to eagerly connect to your Starknet wallet, but seems its instance is not available.',
14
+ );
15
+ }
16
+
17
+ return starknetInstance.isPreauthorized();
18
+ };
19
+ }
@@ -0,0 +1,3 @@
1
+ import { recommended as commonRecommended } from '../common/after.js';
2
+
3
+ export const recommended = [...commonRecommended];
@@ -0,0 +1,5 @@
1
+ import { connectAndUpdateStateForSingleNetwork } from '../common/mod.js';
2
+
3
+ export const recommended = [
4
+ ['connect', connectAndUpdateStateForSingleNetwork] as const,
5
+ ];
@@ -0,0 +1,3 @@
1
+ import { recommended as commonRecommended } from '../common/before.js';
2
+
3
+ export const recommended = [...commonRecommended];
@@ -0,0 +1,18 @@
1
+ import type { StarknetActions } from './types.js';
2
+
3
+ import { ActionBuilder } from '../../mod.js';
4
+ import {
5
+ connectAndUpdateStateForSingleNetwork,
6
+ intoConnecting,
7
+ intoConnectionFinished,
8
+ } from '../common/mod.js';
9
+
10
+ // Actions
11
+ export const connect = () =>
12
+ new ActionBuilder<StarknetActions, 'connect'>('connect')
13
+ .and(connectAndUpdateStateForSingleNetwork)
14
+ .before(intoConnecting)
15
+ .after(intoConnectionFinished);
16
+
17
+ export const canEagerConnect = () =>
18
+ new ActionBuilder<StarknetActions, 'canEagerConnect'>('canEagerConnect');
@@ -0,0 +1,8 @@
1
+ /*
2
+ * TODO: I couldn't found starknet in caip
3
+ * @see https://namespaces.chainagnostic.org/
4
+ */
5
+
6
+ // if the value needs to be change make sure you will update mapCaipNamespaceToLegacyNetworkName as well
7
+ export const CAIP_NAMESPACE = 'starknet';
8
+ export const CAIP_STARKNET_CHAIN_ID = 'SN_MAIN';
@@ -0,0 +1,9 @@
1
+ export * as actions from './actions.js';
2
+ export * as after from './after.js';
3
+ export * as and from './and.js';
4
+ export * as before from './before.js';
5
+ export * as builders from './builders.js';
6
+ export * as utils from './utils.js';
7
+
8
+ export type { ProviderAPI, StarknetActions } from './types.js';
9
+ export { CAIP_NAMESPACE, CAIP_STARKNET_CHAIN_ID } from './constants.js';
@@ -0,0 +1,18 @@
1
+ import type { Accounts } from '../../types/accounts.js';
2
+ import type {
3
+ AutoImplementedActionsByRecommended,
4
+ CommonActions,
5
+ } from '../common/types.js';
6
+
7
+ export interface StarknetActions
8
+ extends AutoImplementedActionsByRecommended, CommonActions {
9
+ connect: (options?: ConnectOptions) => Promise<Accounts>;
10
+ canEagerConnect: () => Promise<boolean>;
11
+ }
12
+
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ export type ProviderAPI = Record<string, any>;
15
+
16
+ export type ConnectOptions = {
17
+ derivationPath?: string;
18
+ };
@@ -0,0 +1,35 @@
1
+ import type { ProviderAPI } from './types.js';
2
+ import type { CaipAccount } from '../../types/accounts.js';
3
+
4
+ import { AccountId } from 'caip';
5
+
6
+ import { LegacyNetworks } from '../../legacy/mod.js';
7
+
8
+ import { CAIP_NAMESPACE, CAIP_STARKNET_CHAIN_ID } from './constants.js';
9
+
10
+ export async function getAccounts(provider: ProviderAPI) {
11
+ const starknetResponse = await provider.connect();
12
+ /*
13
+ * Fallback for wallets that return no response on connect.
14
+ */
15
+ const account = starknetResponse
16
+ ? starknetResponse.publicKey.toString()
17
+ : provider.publicKey.toString();
18
+ return {
19
+ accounts: [account],
20
+ chainId: LegacyNetworks.SOLANA,
21
+ };
22
+ }
23
+
24
+ export function formatAccountsToCAIP(accounts: string[]) {
25
+ return accounts.map(
26
+ (account) =>
27
+ AccountId.format({
28
+ address: account.toString(),
29
+ chainId: {
30
+ namespace: CAIP_NAMESPACE,
31
+ reference: CAIP_STARKNET_CHAIN_ID,
32
+ },
33
+ }) as CaipAccount,
34
+ );
35
+ }
@@ -0,0 +1,27 @@
1
+ import type { SuiActions } from './types.js';
2
+ import type { CanEagerConnect } from '../../hub/namespaces/types.js';
3
+
4
+ import { getInstanceOrThrow } from './mod.js';
5
+
6
+ interface CanEagerConnectParams {
7
+ name: string;
8
+ }
9
+ export function canEagerConnect(
10
+ params: CanEagerConnectParams,
11
+ ): CanEagerConnect<SuiActions> {
12
+ return async () => {
13
+ const wallet = getInstanceOrThrow(params.name);
14
+
15
+ try {
16
+ const connectResult = await wallet.features['standard:connect'].connect({
17
+ silent: true,
18
+ });
19
+ if (connectResult.accounts.length) {
20
+ return true;
21
+ }
22
+ return false;
23
+ } catch {
24
+ return false;
25
+ }
26
+ };
27
+ }
@@ -0,0 +1,77 @@
1
+ import type {
2
+ ChangeAccountSubscriberParams,
3
+ ProviderAPI,
4
+ SuiActions,
5
+ } from './types.js';
6
+ import type { WalletAccount } from '@mysten/wallet-standard';
7
+
8
+ import { ActionBuilder } from '../../mod.js';
9
+ import { CAIP } from '../../utils/mod.js';
10
+ import { ChangeAccountSubscriberBuilder } from '../common/hooks/changeAccountSubscriber.js';
11
+ import {
12
+ type CaipAccount,
13
+ connectAndUpdateStateForSingleNetwork,
14
+ intoConnecting,
15
+ intoConnectionFinished,
16
+ } from '../common/mod.js';
17
+
18
+ import { CAIP_NAMESPACE, CAIP_SUI_CHAIN_ID } from './constants.js';
19
+ import { formatAccountsToCAIP, getInstanceOrThrow } from './utils.js';
20
+
21
+ // Actions
22
+ interface ConnectParams {
23
+ name: string;
24
+ }
25
+
26
+ export const connect = (params: ConnectParams) =>
27
+ new ActionBuilder<SuiActions, 'connect'>('connect')
28
+ .action(async function () {
29
+ const wallet = getInstanceOrThrow(params.name);
30
+ const features = wallet.features;
31
+
32
+ const result = await features['standard:connect'].connect();
33
+
34
+ const accounts = result.accounts.map((account) => {
35
+ return CAIP.AccountId.format({
36
+ address: account.address,
37
+ chainId: {
38
+ namespace: CAIP_NAMESPACE,
39
+ reference: CAIP_SUI_CHAIN_ID,
40
+ },
41
+ }) as CaipAccount;
42
+ });
43
+
44
+ return accounts;
45
+ })
46
+ .and(connectAndUpdateStateForSingleNetwork)
47
+ .before(intoConnecting)
48
+ .after(intoConnectionFinished);
49
+
50
+ export const canEagerConnect = () =>
51
+ new ActionBuilder<SuiActions, 'canEagerConnect'>('canEagerConnect');
52
+
53
+ // Hooks
54
+ export const changeAccountSubscriber = (
55
+ params: ChangeAccountSubscriberParams,
56
+ ) =>
57
+ new ChangeAccountSubscriberBuilder<
58
+ { accounts: readonly WalletAccount[] },
59
+ ProviderAPI,
60
+ SuiActions
61
+ >()
62
+ .getInstance(() => getInstanceOrThrow(params.name))
63
+ /*
64
+ * In some wallets, when a user switches to an account not yet connected to the dApp, it returns null.
65
+ * A null value indicates no access to the account, requiring a disconnect and user reconnection.
66
+ */
67
+ .onSwitchAccount((event, context) => {
68
+ if (!event.payload.accounts?.length) {
69
+ context.action('disconnect');
70
+ event.preventDefault();
71
+ }
72
+ })
73
+ .format(async (_, event) => formatAccountsToCAIP(event.accounts))
74
+ .addEventListener((instance, callback) =>
75
+ instance.features['standard:events'].on('change', callback),
76
+ )
77
+ .removeEventListener((_, __) => {});
@@ -0,0 +1,8 @@
1
+ /*
2
+ * TODO: I couldn't found sui in caip
3
+ * @see https://namespaces.chainagnostic.org/
4
+ */
5
+
6
+ // if the value neeeds to be change make sure you will update mapCaipNamespaceToLegacyNetworkName as well
7
+ export const CAIP_NAMESPACE = 'sui';
8
+ export const CAIP_SUI_CHAIN_ID = 'sui';
@@ -0,0 +1,10 @@
1
+ import type { ChangeAccountSubscriberParams, SuiActions } from './types.js';
2
+ import type { Subscriber, SubscriberCleanUp } from '../../mod.js';
3
+
4
+ import { builders } from './mod.js';
5
+
6
+ export function changeAccountSubscriber(
7
+ params: ChangeAccountSubscriberParams,
8
+ ): [Subscriber<SuiActions>, SubscriberCleanUp<SuiActions>] {
9
+ return builders.changeAccountSubscriber({ name: params.name }).build();
10
+ }
@@ -0,0 +1,8 @@
1
+ export type { ProviderAPI, SuiActions } from './types.js';
2
+
3
+ export * as actions from './actions.js';
4
+ export * as builders from './builders.js';
5
+ export * as hooks from './hooks.js';
6
+ export { getInstanceOrThrow, getInstance } from './utils.js';
7
+
8
+ export { CAIP_NAMESPACE, CAIP_SUI_CHAIN_ID } from './constants.js';