@layerswap/wallet-stellar 2.1.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 (47) hide show
  1. package/dist/esm/constants.js +8 -0
  2. package/dist/esm/index.js +50 -0
  3. package/dist/esm/service/StellarConnectionService.js +205 -0
  4. package/dist/esm/service/StellarWalletConnectModule.js +218 -0
  5. package/dist/esm/service/createStellarConnection.js +63 -0
  6. package/dist/esm/service/stellarConnector.js +23 -0
  7. package/dist/esm/service/stellarKitManager.js +272 -0
  8. package/dist/esm/service/stellarStore.js +14 -0
  9. package/dist/esm/stellarBalanceProvider.js +49 -0
  10. package/dist/esm/stellarBalances.js +40 -0
  11. package/dist/esm/stellarGasProvider.js +22 -0
  12. package/dist/esm/stellarNetwork.js +34 -0
  13. package/dist/esm/stellarServers.js +51 -0
  14. package/dist/esm/transferProvider/createStellarTransfer.js +122 -0
  15. package/dist/esm/transferProvider/validateStellarXdr.js +249 -0
  16. package/dist/tsconfig.tsbuildinfo +1 -0
  17. package/dist/types/constants.d.ts +5 -0
  18. package/dist/types/constants.d.ts.map +1 -0
  19. package/dist/types/index.d.ts +14 -0
  20. package/dist/types/index.d.ts.map +1 -0
  21. package/dist/types/service/StellarConnectionService.d.ts +44 -0
  22. package/dist/types/service/StellarConnectionService.d.ts.map +1 -0
  23. package/dist/types/service/StellarWalletConnectModule.d.ts +86 -0
  24. package/dist/types/service/StellarWalletConnectModule.d.ts.map +1 -0
  25. package/dist/types/service/createStellarConnection.d.ts +7 -0
  26. package/dist/types/service/createStellarConnection.d.ts.map +1 -0
  27. package/dist/types/service/stellarConnector.d.ts +4 -0
  28. package/dist/types/service/stellarConnector.d.ts.map +1 -0
  29. package/dist/types/service/stellarKitManager.d.ts +37 -0
  30. package/dist/types/service/stellarKitManager.d.ts.map +1 -0
  31. package/dist/types/service/stellarStore.d.ts +24 -0
  32. package/dist/types/service/stellarStore.d.ts.map +1 -0
  33. package/dist/types/stellarBalanceProvider.d.ts +6 -0
  34. package/dist/types/stellarBalanceProvider.d.ts.map +1 -0
  35. package/dist/types/stellarBalances.d.ts +22 -0
  36. package/dist/types/stellarBalances.d.ts.map +1 -0
  37. package/dist/types/stellarGasProvider.d.ts +11 -0
  38. package/dist/types/stellarGasProvider.d.ts.map +1 -0
  39. package/dist/types/stellarNetwork.d.ts +7 -0
  40. package/dist/types/stellarNetwork.d.ts.map +1 -0
  41. package/dist/types/stellarServers.d.ts +5 -0
  42. package/dist/types/stellarServers.d.ts.map +1 -0
  43. package/dist/types/transferProvider/createStellarTransfer.d.ts +3 -0
  44. package/dist/types/transferProvider/createStellarTransfer.d.ts.map +1 -0
  45. package/dist/types/transferProvider/validateStellarXdr.d.ts +22 -0
  46. package/dist/types/transferProvider/validateStellarXdr.d.ts.map +1 -0
  47. package/package.json +63 -0
@@ -0,0 +1,8 @@
1
+ import KnownInternalNames from '@layerswap/utils/known-ids';
2
+ export const name = 'Stellar';
3
+ export const id = 'stellar';
4
+ export const supportedNetworkNames = [
5
+ KnownInternalNames.Networks.StellarMainnet,
6
+ KnownInternalNames.Networks.StellarTestnet,
7
+ ];
8
+ export const STELLAR_SESSION_KEY = 'layerswap:stellar-wallet';
@@ -0,0 +1,50 @@
1
+ import { LazyBalanceProvider, LazyGasProvider, NetworkType, } from '@layerswap/widget-types';
2
+ import { id } from './constants';
3
+ import { createStellarConnection } from './service/createStellarConnection';
4
+ import { stellarKitManager } from './service/stellarKitManager';
5
+ import { createStellarTransfer } from './transferProvider/createStellarTransfer';
6
+ export function createStellarProvider(config = {}) {
7
+ const { walletConnect, customConnection, balanceProviders, gasProviders, transferProviders, } = config;
8
+ const initialize = () => {
9
+ void stellarKitManager.init(walletConnect).catch(error => {
10
+ console.error('[Stellar] Failed to initialize wallet connectors', error);
11
+ });
12
+ };
13
+ const init = (_context) => {
14
+ initialize();
15
+ return () => stellarKitManager.dispose();
16
+ };
17
+ const createConnection = (props) => {
18
+ initialize();
19
+ return customConnection
20
+ ? customConnection(props)
21
+ : createStellarConnection(props, { walletConnectProjectId: walletConnect?.projectId });
22
+ };
23
+ const defaultBalanceProviders = [
24
+ new LazyBalanceProvider(network => network.type === NetworkType.Stellar, () => import('./stellarBalanceProvider').then(module => new module.StellarBalanceProvider())),
25
+ ];
26
+ const finalBalanceProviders = balanceProviders !== undefined
27
+ ? (Array.isArray(balanceProviders) ? balanceProviders : [balanceProviders])
28
+ : defaultBalanceProviders;
29
+ const defaultGasProviders = [
30
+ new LazyGasProvider(network => network.type === NetworkType.Stellar, () => import('./stellarGasProvider').then(module => new module.StellarGasProvider())),
31
+ ];
32
+ const finalGasProviders = gasProviders !== undefined
33
+ ? (Array.isArray(gasProviders) ? gasProviders : [gasProviders])
34
+ : defaultGasProviders;
35
+ const finalTransferProviders = transferProviders !== undefined
36
+ ? (Array.isArray(transferProviders) ? transferProviders : [transferProviders])
37
+ : [createStellarTransfer];
38
+ return {
39
+ id,
40
+ init,
41
+ createConnection,
42
+ balanceProvider: finalBalanceProviders,
43
+ gasProvider: finalGasProviders,
44
+ transferProvider: finalTransferProviders,
45
+ };
46
+ }
47
+ export { createStellarConnection } from './service/createStellarConnection';
48
+ export { stellarStore } from './service/stellarStore';
49
+ export { stellarKitManager } from './service/stellarKitManager';
50
+ export { validateStellarOperationXdr, validateStellarXdr } from './transferProvider/validateStellarXdr';
@@ -0,0 +1,205 @@
1
+ import { NetworkType } from '@layerswap/widget-types';
2
+ import { buildDeepLink, clearPendingDynamicWcMetadata, createRegistryConnector, getDynamicWcMetadata, getPendingDynamicWcMetadata, isWalletConnectRegistryConnector, setDynamicWcMetadata, setPendingMetadataForRegistry, subscribeDisplayUri, walletIconResolver, } from '@layerswap/wallet-core';
3
+ import { id as PROVIDER_ID, name as PROVIDER_NAME } from '../constants';
4
+ import { STELLAR_APPKIT_WALLET_CONNECT_ID } from './StellarWalletConnectModule';
5
+ import { stellarKitManager } from './stellarKitManager';
6
+ import { stellarStore } from './stellarStore';
7
+ import { toStellarConnector } from './stellarConnector';
8
+ export class StellarConnectionService {
9
+ constructor(kitManager = stellarKitManager) {
10
+ this.kitManager = kitManager;
11
+ this.networks = [];
12
+ this.networksKey = '';
13
+ this.deps = {};
14
+ }
15
+ setNetworks(networks, networkAdapter) {
16
+ const key = networks.map(network => networkAdapter.getId(network)).join('|');
17
+ if (this.networksKey === key)
18
+ return;
19
+ this.networks = networks;
20
+ this.networkAdapter = networkAdapter;
21
+ this.networksKey = key;
22
+ }
23
+ configure(deps) {
24
+ this.deps = { ...this.deps, ...deps };
25
+ }
26
+ getAvailableConnectors() {
27
+ const isMobilePlatform = this.deps.isMobilePlatform ?? false;
28
+ const configured = stellarStore.getState().wallets
29
+ .filter(wallet => wallet.id !== STELLAR_APPKIT_WALLET_CONNECT_ID)
30
+ .map(toStellarConnector)
31
+ .filter(connector => !isMobilePlatform || connector.isMobileSupported);
32
+ const recent = (this.deps.recentConnectors ?? [])
33
+ .filter(connector => !isMobilePlatform || connector.isMobileSupported);
34
+ return [...configured, ...recent];
35
+ }
36
+ getAdditionalConnectors() {
37
+ const isMobilePlatform = this.deps.isMobilePlatform ?? false;
38
+ return (this.deps.registryConnectors ?? [])
39
+ .filter(wallet => !isMobilePlatform || wallet.isMobileSupported)
40
+ .map(wallet => createRegistryConnector(wallet, isMobilePlatform, PROVIDER_NAME));
41
+ }
42
+ getConnectedWallets() {
43
+ const { wallets, activeWalletId, activeAddress } = stellarStore.getState();
44
+ if (!activeWalletId || !activeAddress)
45
+ return [];
46
+ const snapshot = wallets.find(wallet => wallet.id === activeWalletId);
47
+ if (!snapshot)
48
+ return [];
49
+ return [this.resolveWallet(snapshot, activeAddress)];
50
+ }
51
+ async connectWallet({ connector }) {
52
+ const wallets = stellarStore.getState().wallets;
53
+ const registryConnector = isWalletConnectRegistryConnector(connector) ? connector : undefined;
54
+ const wallet = registryConnector
55
+ ? wallets.find(item => item.type === 'BRIDGE_WALLET')
56
+ : wallets.find(item => item.id === connector.id);
57
+ if (!wallet)
58
+ throw new Error('Stellar wallet connector not found');
59
+ const isWalletConnect = wallet.type === 'BRIDGE_WALLET';
60
+ const isMobilePlatform = this.deps.isMobilePlatform ?? false;
61
+ const mobile = registryConnector?.mobile;
62
+ const deepLink = mobile?.native || mobile?.universal || undefined;
63
+ const resolveURI = registryConnector && mobile && deepLink
64
+ ? (uri) => buildDeepLink({ id: registryConnector.id, mobile }, uri)
65
+ : undefined;
66
+ const useAppKit = isWalletConnect && isMobilePlatform && !registryConnector;
67
+ const kitWallet = useAppKit ? wallets.find(item => item.id === STELLAR_APPKIT_WALLET_CONNECT_ID) ?? wallet : wallet;
68
+ let unsubscribeDisplayUri;
69
+ const setSelectedConnectorIfCurrent = (next) => {
70
+ if (!this.deps.getSelectedConnector) {
71
+ this.deps.setSelectedConnector?.(next);
72
+ return;
73
+ }
74
+ const current = this.deps.getSelectedConnector();
75
+ if (current?.id === connector.id)
76
+ this.deps.setSelectedConnector?.(next);
77
+ };
78
+ try {
79
+ if (isWalletConnect) {
80
+ setPendingMetadataForRegistry(PROVIDER_ID, registryConnector ? { ...registryConnector, deepLink } : undefined);
81
+ const wantsQrModal = !useAppKit && (!isMobilePlatform || !resolveURI);
82
+ if (wantsQrModal) {
83
+ this.deps.setSelectedConnector?.({
84
+ ...connector,
85
+ qr: { state: 'loading', value: undefined },
86
+ showQrCode: true,
87
+ });
88
+ }
89
+ if (!useAppKit) {
90
+ unsubscribeDisplayUri = subscribeDisplayUri({
91
+ source: this.kitManager,
92
+ resolveURI,
93
+ isMobilePlatform,
94
+ onQr: qr => setSelectedConnectorIfCurrent({ ...connector, qr, showQrCode: true }),
95
+ });
96
+ }
97
+ if (registryConnector)
98
+ this.deps.addRecentConnector?.(registryConnector);
99
+ }
100
+ const { address } = await this.kitManager.connect(kitWallet.id);
101
+ if (registryConnector) {
102
+ setDynamicWcMetadata(PROVIDER_ID, address, {
103
+ name: registryConnector.name,
104
+ icon: registryConnector.icon || '',
105
+ id: registryConnector.id,
106
+ deepLink,
107
+ });
108
+ }
109
+ return this.resolveWallet(kitWallet, address);
110
+ }
111
+ finally {
112
+ unsubscribeDisplayUri?.();
113
+ if (isWalletConnect)
114
+ clearPendingDynamicWcMetadata(PROVIDER_ID);
115
+ }
116
+ }
117
+ async disconnectWallets() {
118
+ await this.kitManager.disconnect();
119
+ }
120
+ async requestAdditionalConnectors(params = {}) {
121
+ if (!this.deps.requestRegistryConnectors || !this.hasWalletConnectTransport()) {
122
+ return { connectors: [], nextPage: null, totalCount: 0 };
123
+ }
124
+ const result = await this.deps.requestRegistryConnectors(params);
125
+ const isMobilePlatform = this.deps.isMobilePlatform ?? false;
126
+ const connectors = result.connectors
127
+ .filter(wallet => !isMobilePlatform || wallet.isMobileSupported)
128
+ .map(wallet => createRegistryConnector(wallet, isMobilePlatform, PROVIDER_NAME));
129
+ return {
130
+ connectors,
131
+ nextPage: result.nextPage,
132
+ totalCount: result.totalCount,
133
+ };
134
+ }
135
+ buildProvider() {
136
+ const connectedWallets = this.getConnectedWallets();
137
+ const activeWallet = connectedWallets[0];
138
+ const supportedNetworks = this.getSupportedNetworks();
139
+ const networkLogo = this.getNetworkLogo();
140
+ return {
141
+ connectWallet: this.connectWallet.bind(this),
142
+ disconnectWallets: this.disconnectWallets.bind(this),
143
+ requestAdditionalConnectors: this.hasWalletConnectTransport()
144
+ ? this.requestAdditionalConnectors.bind(this)
145
+ : undefined,
146
+ availableConnectors: this.getAvailableConnectors(),
147
+ additionalConnectors: this.hasWalletConnectTransport()
148
+ ? this.getAdditionalConnectors()
149
+ : undefined,
150
+ connectedWallets,
151
+ activeWallet,
152
+ autofillSupportedNetworks: supportedNetworks,
153
+ withdrawalSupportedNetworks: supportedNetworks,
154
+ asSourceSupportedNetworks: supportedNetworks,
155
+ name: PROVIDER_NAME,
156
+ id: PROVIDER_ID,
157
+ capabilities: this.hasWalletConnectTransport() ? {
158
+ walletConnectRegistry: {
159
+ networkTypes: [NetworkType.Stellar],
160
+ },
161
+ } : undefined,
162
+ providerIcon: networkLogo,
163
+ ready: stellarStore.getState().ready,
164
+ };
165
+ }
166
+ resolveWallet(snapshot, address) {
167
+ const supportedNetworks = this.getSupportedNetworks();
168
+ const isWalletConnect = snapshot.type === 'BRIDGE_WALLET';
169
+ const dynamicMetadata = isWalletConnect
170
+ ? getDynamicWcMetadata(PROVIDER_ID, address) || getPendingDynamicWcMetadata(PROVIDER_ID)
171
+ : null;
172
+ const displayName = dynamicMetadata?.name || snapshot.name;
173
+ const walletId = dynamicMetadata?.id || snapshot.id;
174
+ const icon = dynamicMetadata?.icon || snapshot.icon;
175
+ return {
176
+ id: walletId,
177
+ address,
178
+ addresses: [address],
179
+ displayName: `${displayName} - Stellar`,
180
+ providerName: PROVIDER_NAME,
181
+ isActive: true,
182
+ icon: walletIconResolver(address, icon),
183
+ networkIcon: this.getNetworkLogo(),
184
+ disconnect: () => this.disconnectWallets(),
185
+ autofillSupportedNetworks: supportedNetworks,
186
+ withdrawalSupportedNetworks: supportedNetworks,
187
+ asSourceSupportedNetworks: supportedNetworks,
188
+ metadata: { deepLink: dynamicMetadata?.deepLink },
189
+ };
190
+ }
191
+ hasWalletConnectTransport() {
192
+ return stellarStore.getState().wallets.some(wallet => wallet.type === 'BRIDGE_WALLET');
193
+ }
194
+ getNetworkLogo() {
195
+ const network = this.networks.find(item => this.networkAdapter?.isStellarNetwork(item));
196
+ return network && this.networkAdapter ? this.networkAdapter.getIcon(network) : undefined;
197
+ }
198
+ getSupportedNetworks() {
199
+ if (!this.networkAdapter)
200
+ return [];
201
+ return this.networks
202
+ .filter(network => this.networkAdapter?.isStellarNetwork(network))
203
+ .map(network => this.networkAdapter.getId(network));
204
+ }
205
+ }
@@ -0,0 +1,218 @@
1
+ import { ModuleType, Networks } from '@creit.tech/stellar-wallets-kit/types';
2
+ const STELLAR_WALLET_CONNECT_STORAGE_PREFIX = 'layerswapStellarWalletConnect';
3
+ export const STELLAR_WALLET_CONNECT_ID = 'wallet_connect';
4
+ export const STELLAR_APPKIT_WALLET_CONNECT_ID = 'wallet_connect_appkit';
5
+ export const StellarWalletConnectChain = {
6
+ Public: 'stellar:pubnet',
7
+ Testnet: 'stellar:testnet',
8
+ };
9
+ const StellarWalletConnectMethod = {
10
+ Sign: 'stellar_signXDR',
11
+ SignAndSubmit: 'stellar_signAndSubmitXDR',
12
+ SignMessage: 'stellar_signMessage',
13
+ SignAuthEntry: 'stellar_signAuthEntry',
14
+ };
15
+ const stellarAccounts = (session) => session.namespaces.stellar?.accounts
16
+ ?.map(account => account.split(':')[2])
17
+ .filter((address) => !!address) ?? [];
18
+ const stellarAccount = (session, expectedAddress) => {
19
+ const accounts = stellarAccounts(session);
20
+ return expectedAddress
21
+ ? accounts.find(address => address === expectedAddress)
22
+ : accounts[0];
23
+ };
24
+ /**
25
+ * Stellar Wallets Kit module backed directly by WalletConnect SignClient.
26
+ * The Kit still owns wallet selection and signing dispatch, while Layerswap owns
27
+ * presentation of the emitted `wc:` URI through its shared QR modal.
28
+ */
29
+ export class StellarWalletConnectModule {
30
+ constructor(config, clientFactory = async () => {
31
+ const { SignClient } = await import('@walletconnect/sign-client');
32
+ return SignClient.init({
33
+ projectId: config.projectId,
34
+ metadata: {
35
+ name: config.name,
36
+ description: config.description,
37
+ url: config.url,
38
+ icons: config.icons,
39
+ },
40
+ customStoragePrefix: STELLAR_WALLET_CONNECT_STORAGE_PREFIX,
41
+ });
42
+ }, chains = [StellarWalletConnectChain.Public, StellarWalletConnectChain.Testnet]) {
43
+ this.config = config;
44
+ this.clientFactory = clientFactory;
45
+ this.chains = chains;
46
+ this.moduleType = ModuleType.BRIDGE_WALLET;
47
+ this.productId = STELLAR_WALLET_CONNECT_ID;
48
+ this.productName = 'WalletConnect';
49
+ this.productUrl = 'https://walletconnect.com/';
50
+ this.productIcon = 'https://stellar.creit.tech/wallet-icons/walletconnect.png';
51
+ this.displayUriListeners = new Set();
52
+ this.sessionDeleteListeners = new Set();
53
+ }
54
+ async isAvailable() {
55
+ return typeof window !== 'undefined';
56
+ }
57
+ async isPlatformWrapper() {
58
+ if (typeof window === 'undefined')
59
+ return false;
60
+ const stellar = window.stellar;
61
+ return stellar?.provider === 'freighter' && stellar.platform === 'mobile';
62
+ }
63
+ onDisplayUri(listener) {
64
+ this.displayUriListeners.add(listener);
65
+ return () => this.displayUriListeners.delete(listener);
66
+ }
67
+ onSessionDelete(listener) {
68
+ this.sessionDeleteListeners.add(listener);
69
+ return () => this.sessionDeleteListeners.delete(listener);
70
+ }
71
+ warmup() {
72
+ void this.getClient().catch(() => {
73
+ // A real connect attempt reports initialization failures to the UI.
74
+ });
75
+ }
76
+ async getAddress() {
77
+ const client = await this.getClient();
78
+ const chains = this.chains;
79
+ const { uri, approval } = await client.connect({
80
+ requiredNamespaces: {
81
+ stellar: {
82
+ chains,
83
+ methods: [StellarWalletConnectMethod.Sign],
84
+ events: [],
85
+ },
86
+ },
87
+ optionalNamespaces: {
88
+ stellar: {
89
+ chains,
90
+ methods: [
91
+ StellarWalletConnectMethod.SignAndSubmit,
92
+ StellarWalletConnectMethod.SignAuthEntry,
93
+ StellarWalletConnectMethod.SignMessage,
94
+ ],
95
+ events: [],
96
+ },
97
+ },
98
+ });
99
+ if (uri) {
100
+ for (const listener of this.displayUriListeners)
101
+ listener(uri);
102
+ }
103
+ const session = await approval();
104
+ const address = stellarAccount(session);
105
+ if (!address) {
106
+ await client.disconnect({
107
+ topic: session.topic,
108
+ reason: { code: -1, message: 'Session approved without a Stellar account' },
109
+ });
110
+ throw new Error('The approved WalletConnect session has no Stellar account');
111
+ }
112
+ this.activeTopic = session.topic;
113
+ return { address };
114
+ }
115
+ async getConnectedAddress(expectedAddress) {
116
+ const client = await this.getClient();
117
+ const session = this.findSession(client, expectedAddress);
118
+ const address = session && stellarAccount(session, expectedAddress);
119
+ if (!address) {
120
+ throw new Error('The Stellar WalletConnect session expired; reconnect the wallet');
121
+ }
122
+ this.activeTopic = session.topic;
123
+ return { address };
124
+ }
125
+ async signTransaction(xdr, opts) {
126
+ const result = await this.request(StellarWalletConnectMethod.Sign, { xdr }, opts?.networkPassphrase, opts?.address);
127
+ if (!result?.signedXDR)
128
+ throw new Error('WalletConnect wallet returned no signed Stellar XDR');
129
+ return { signedTxXdr: result.signedXDR, signerAddress: opts?.address };
130
+ }
131
+ async signAndSubmitTransaction(xdr, opts) {
132
+ const result = await this.request(StellarWalletConnectMethod.SignAndSubmit, { xdr }, opts?.networkPassphrase, opts?.address);
133
+ if (result.status !== 'success' && result.status !== 'pending') {
134
+ throw new Error(`Unexpected Stellar WalletConnect status: ${result.status}`);
135
+ }
136
+ return { status: result.status };
137
+ }
138
+ async signAuthEntry(authEntry, opts) {
139
+ return this.request(StellarWalletConnectMethod.SignAuthEntry, { entryXdr: authEntry }, opts?.networkPassphrase, opts?.address);
140
+ }
141
+ async signMessage(message, opts) {
142
+ const result = await this.request(StellarWalletConnectMethod.SignMessage, { message }, opts?.networkPassphrase, opts?.address);
143
+ return { signedMessage: result.signature, signerAddress: result.signerAddress };
144
+ }
145
+ async getNetwork() {
146
+ throw new Error('WalletConnect does not expose the active Stellar network');
147
+ }
148
+ async disconnect() {
149
+ const client = this.client;
150
+ if (!client)
151
+ return;
152
+ const sessions = client.session.values.filter(session => stellarAccount(session));
153
+ await Promise.all(sessions.map(session => client.disconnect({
154
+ topic: session.topic,
155
+ reason: { code: -1, message: 'Session closed' },
156
+ })));
157
+ }
158
+ dispose() {
159
+ if (this.client && this.sessionEndedHandler) {
160
+ this.client.off('session_delete', this.sessionEndedHandler);
161
+ this.client.off('session_expire', this.sessionEndedHandler);
162
+ }
163
+ this.displayUriListeners.clear();
164
+ this.sessionDeleteListeners.clear();
165
+ this.sessionEndedHandler = undefined;
166
+ this.activeTopic = undefined;
167
+ this.client = undefined;
168
+ this.clientPromise = undefined;
169
+ }
170
+ async getClient() {
171
+ if (this.client)
172
+ return this.client;
173
+ if (!this.clientPromise) {
174
+ this.clientPromise = this.clientFactory().then(client => {
175
+ this.client = client;
176
+ this.sessionEndedHandler = event => {
177
+ if (this.activeTopic && event.topic !== this.activeTopic)
178
+ return;
179
+ this.activeTopic = undefined;
180
+ for (const listener of this.sessionDeleteListeners)
181
+ listener();
182
+ };
183
+ client.on('session_delete', this.sessionEndedHandler);
184
+ client.on('session_expire', this.sessionEndedHandler);
185
+ return client;
186
+ }).finally(() => {
187
+ this.clientPromise = undefined;
188
+ });
189
+ }
190
+ return this.clientPromise;
191
+ }
192
+ async request(method, params, networkPassphrase, address) {
193
+ const client = await this.getClient();
194
+ const session = this.findSession(client, address);
195
+ if (!session) {
196
+ throw new Error('No active Stellar WalletConnect session for the selected address');
197
+ }
198
+ this.activeTopic = session.topic;
199
+ const chainId = networkPassphrase === Networks.PUBLIC
200
+ ? StellarWalletConnectChain.Public
201
+ : StellarWalletConnectChain.Testnet;
202
+ return client.request({
203
+ topic: session.topic,
204
+ chainId,
205
+ request: { method, params },
206
+ });
207
+ }
208
+ findSession(client, address) {
209
+ const active = this.activeTopic
210
+ ? client.session.values.find(session => (session.topic === this.activeTopic && stellarAccount(session, address)))
211
+ : undefined;
212
+ if (active)
213
+ return active;
214
+ return [...client.session.values]
215
+ .reverse()
216
+ .find(session => stellarAccount(session, address));
217
+ }
218
+ }
@@ -0,0 +1,63 @@
1
+ import { connectModalStore, createMemoizedConnectionStore, getAdditionalConnectorsStore } from '@layerswap/wallet-core';
2
+ import { isMobile } from '@layerswap/utils';
3
+ import { id as PROVIDER_ID } from '../constants';
4
+ import { StellarConnectionService } from './StellarConnectionService';
5
+ import { stellarKitManager } from './stellarKitManager';
6
+ import { stellarStore } from './stellarStore';
7
+ export function createStellarConnection(initialProps, options = {}) {
8
+ let networks = initialProps.networks;
9
+ let networkAdapter = initialProps.networkAdapter;
10
+ const service = new StellarConnectionService();
11
+ service.setNetworks(networks, networkAdapter);
12
+ const additionalConnectorsStore = options.walletConnectProjectId
13
+ ? getAdditionalConnectorsStore(PROVIDER_ID, options.walletConnectProjectId)
14
+ : undefined;
15
+ service.configure({
16
+ setSelectedConnector: connector => connectModalStore.setSelectedConnector(connector),
17
+ getSelectedConnector: () => connectModalStore.getSnapshot().selectedConnector,
18
+ addRecentConnector: additionalConnectorsStore?.addRecentConnector,
19
+ requestRegistryConnectors: additionalConnectorsStore?.requestAdditionalConnectors,
20
+ registryConnectors: additionalConnectorsStore?.getSnapshot().browseConnectors,
21
+ recentConnectors: additionalConnectorsStore?.getSnapshot().recentConnectors,
22
+ isMobilePlatform: isMobile(),
23
+ });
24
+ return createMemoizedConnectionStore({
25
+ computeInputs: () => {
26
+ const state = stellarStore.getState();
27
+ const additional = additionalConnectorsStore?.getSnapshot();
28
+ return {
29
+ wallets: state.wallets,
30
+ activeWalletId: state.activeWalletId,
31
+ activeAddress: state.activeAddress,
32
+ networkPassphrase: state.networkPassphrase,
33
+ ready: state.ready,
34
+ error: state.error,
35
+ browseConnectors: additional?.browseConnectors,
36
+ recentConnectors: additional?.recentConnectors,
37
+ networks,
38
+ };
39
+ },
40
+ buildSnapshot: inputs => {
41
+ service.configure({
42
+ registryConnectors: inputs.browseConnectors,
43
+ recentConnectors: inputs.recentConnectors,
44
+ });
45
+ return service.buildProvider();
46
+ },
47
+ subscribe: sync => [
48
+ stellarStore.subscribe(sync),
49
+ ...(additionalConnectorsStore ? [additionalConnectorsStore.subscribe(sync)] : []),
50
+ connectModalStore.subscribe(() => {
51
+ if (!connectModalStore.getSnapshot().isWalletModalOpen)
52
+ return;
53
+ void additionalConnectorsStore?.ensureBrowseLoaded();
54
+ stellarKitManager.warmUpWalletConnect();
55
+ }),
56
+ ],
57
+ onUpdateProps: nextProps => {
58
+ networks = nextProps.networks;
59
+ networkAdapter = nextProps.networkAdapter;
60
+ service.setNetworks(networks, networkAdapter);
61
+ },
62
+ });
63
+ }
@@ -0,0 +1,23 @@
1
+ import { name as PROVIDER_NAME } from '../constants';
2
+ // Wallets Kit reports both installed extensions and wallets that are usable
3
+ // without installation as `isAvailable`. Albedo/xBull open their own web flow,
4
+ // while BRIDGE_WALLET modules (currently WalletConnect) use a pairing transport.
5
+ // Neither kind should ever be presented as a missing browser extension.
6
+ const LOADABLE_WALLET_IDS = new Set(['albedo', 'xbull']);
7
+ export function toStellarConnector(wallet) {
8
+ const isBridgeWallet = wallet.type === 'BRIDGE_WALLET';
9
+ const isLoadable = isBridgeWallet || LOADABLE_WALLET_IDS.has(wallet.id);
10
+ const isUnavailable = !isLoadable && !wallet.isAvailable && !wallet.isPlatformWrapper;
11
+ return {
12
+ id: wallet.id,
13
+ name: wallet.name,
14
+ icon: wallet.icon,
15
+ type: isBridgeWallet ? 'walletConnect' : isUnavailable ? 'other' : 'injected',
16
+ installUrl: wallet.url,
17
+ hasBrowserExtension: isBridgeWallet ? false : undefined,
18
+ extensionNotFound: isUnavailable,
19
+ isLoadable,
20
+ isMobileSupported: isLoadable || wallet.isPlatformWrapper,
21
+ providerName: PROVIDER_NAME,
22
+ };
23
+ }