@kheopskit/core 1.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATING_TO_V4.md +259 -0
- package/README.md +67 -0
- package/dist/chunk-4RBYRNY3.mjs +164 -0
- package/dist/chunk-4RBYRNY3.mjs.map +1 -0
- package/dist/chunk-BWUUHUDK.mjs +24 -0
- package/dist/chunk-BWUUHUDK.mjs.map +1 -0
- package/dist/chunk-D3EQMFZ2.js +24 -0
- package/dist/chunk-D3EQMFZ2.js.map +1 -0
- package/dist/chunk-FIAL4HTE.js +1 -0
- package/dist/chunk-FIAL4HTE.js.map +1 -0
- package/dist/chunk-KWFQDD7E.mjs +578 -0
- package/dist/chunk-KWFQDD7E.mjs.map +1 -0
- package/dist/chunk-NU46D4MZ.js +578 -0
- package/dist/chunk-NU46D4MZ.js.map +1 -0
- package/dist/chunk-PNPPI5CH.mjs +201 -0
- package/dist/chunk-PNPPI5CH.mjs.map +1 -0
- package/dist/chunk-SIUWQBT4.js +201 -0
- package/dist/chunk-SIUWQBT4.js.map +1 -0
- package/dist/chunk-TMAPQWW2.js +164 -0
- package/dist/chunk-TMAPQWW2.js.map +1 -0
- package/dist/chunk-YFD3IKK5.mjs +1 -0
- package/dist/chunk-YFD3IKK5.mjs.map +1 -0
- package/dist/ethereum.d.mts +60 -0
- package/dist/ethereum.d.ts +60 -0
- package/dist/ethereum.js +332 -0
- package/dist/ethereum.js.map +1 -0
- package/dist/ethereum.mjs +332 -0
- package/dist/ethereum.mjs.map +1 -0
- package/dist/getCachedObservable-C4E8dfMp.d.mts +20 -0
- package/dist/getCachedObservable-C4E8dfMp.d.ts +20 -0
- package/dist/index.d.mts +44 -270
- package/dist/index.d.ts +44 -270
- package/dist/index.js +160 -1394
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -1387
- package/dist/index.mjs.map +1 -1
- package/dist/internal.d.mts +86 -0
- package/dist/internal.d.ts +86 -0
- package/dist/internal.js +32 -0
- package/dist/internal.js.map +1 -0
- package/dist/internal.mjs +32 -0
- package/dist/internal.mjs.map +1 -0
- package/dist/polkadot.d.mts +69 -0
- package/dist/polkadot.d.ts +69 -0
- package/dist/polkadot.js +314 -0
- package/dist/polkadot.js.map +1 -0
- package/dist/polkadot.mjs +314 -0
- package/dist/polkadot.mjs.map +1 -0
- package/dist/solana.d.mts +97 -0
- package/dist/solana.d.ts +97 -0
- package/dist/solana.js +466 -0
- package/dist/solana.js.map +1 -0
- package/dist/solana.mjs +466 -0
- package/dist/solana.mjs.map +1 -0
- package/dist/types-BNzRUNw-.d.mts +319 -0
- package/dist/types-BNzRUNw-.d.ts +319 -0
- package/package.json +76 -16
package/dist/solana.js
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }require('./chunk-FIAL4HTE.js');
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
var _chunkNU46D4MZjs = require('./chunk-NU46D4MZ.js');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
var _chunkSIUWQBT4js = require('./chunk-SIUWQBT4.js');
|
|
14
|
+
|
|
15
|
+
// src/api/solana/chains.ts
|
|
16
|
+
var DEFAULT_SOLANA_CHAIN = "solana:mainnet";
|
|
17
|
+
var SOLANA_CHAIN_IDS = [
|
|
18
|
+
"solana:mainnet",
|
|
19
|
+
"solana:devnet",
|
|
20
|
+
"solana:testnet",
|
|
21
|
+
"solana:localnet"
|
|
22
|
+
];
|
|
23
|
+
var isSolanaChainId = (value) => typeof value === "string" && SOLANA_CHAIN_IDS.includes(value);
|
|
24
|
+
var SOLANA_CHAIN_TO_CAIP2 = {
|
|
25
|
+
"solana:mainnet": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
26
|
+
"solana:devnet": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
|
|
27
|
+
"solana:testnet": "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z"
|
|
28
|
+
};
|
|
29
|
+
var getSolanaCaip2 = (chain) => {
|
|
30
|
+
const caip2 = SOLANA_CHAIN_TO_CAIP2[chain];
|
|
31
|
+
if (!caip2)
|
|
32
|
+
throw new (0, _chunkNU46D4MZjs.KheopskitError)(
|
|
33
|
+
"UNSUPPORTED_CHAIN",
|
|
34
|
+
`Solana chain "${chain}" cannot be used over WalletConnect (no CAIP-2 id).`
|
|
35
|
+
);
|
|
36
|
+
return caip2;
|
|
37
|
+
};
|
|
38
|
+
var CAIP2_TO_SOLANA_CHAIN = Object.fromEntries(
|
|
39
|
+
Object.entries(SOLANA_CHAIN_TO_CAIP2).map(([chain, caip2]) => [
|
|
40
|
+
caip2,
|
|
41
|
+
chain
|
|
42
|
+
])
|
|
43
|
+
);
|
|
44
|
+
var getSolanaChainIdFromCaip2 = (caip2) => CAIP2_TO_SOLANA_CHAIN[caip2];
|
|
45
|
+
|
|
46
|
+
// src/api/solana/accounts.ts
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
var _rxjs = require('rxjs');
|
|
56
|
+
|
|
57
|
+
// src/api/solana/signer.ts
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
var _kit = require('@solana/kit');
|
|
67
|
+
var SOLANA_SIGN_MESSAGE = "solana:signMessage";
|
|
68
|
+
var SOLANA_SIGN_TRANSACTION = "solana:signTransaction";
|
|
69
|
+
var SOLANA_SIGN_AND_SEND_TRANSACTION = "solana:signAndSendTransaction";
|
|
70
|
+
var requireFeature = (wallet, name) => {
|
|
71
|
+
const feature = wallet.features[name];
|
|
72
|
+
if (!feature)
|
|
73
|
+
throw new (0, _chunkNU46D4MZjs.KheopskitError)(
|
|
74
|
+
"FEATURE_NOT_SUPPORTED",
|
|
75
|
+
`wallet "${wallet.name}" does not support ${name}`
|
|
76
|
+
);
|
|
77
|
+
return feature;
|
|
78
|
+
};
|
|
79
|
+
var createInjectedSolanaSigner = (wallet, account, chain) => {
|
|
80
|
+
const signerAddress = _kit.address.call(void 0, account.address);
|
|
81
|
+
return {
|
|
82
|
+
address: signerAddress,
|
|
83
|
+
modifyAndSignMessages: async (messages) => {
|
|
84
|
+
const feature = requireFeature(
|
|
85
|
+
wallet,
|
|
86
|
+
SOLANA_SIGN_MESSAGE
|
|
87
|
+
);
|
|
88
|
+
const outputs = await feature.signMessage(
|
|
89
|
+
...messages.map((m) => ({ account, message: m.content }))
|
|
90
|
+
);
|
|
91
|
+
return messages.map((m, i) => {
|
|
92
|
+
const output = outputs[i];
|
|
93
|
+
if (!output) throw new Error("[kheopskit] missing signMessage output");
|
|
94
|
+
return {
|
|
95
|
+
content: output.signedMessage,
|
|
96
|
+
signatures: {
|
|
97
|
+
...m.signatures,
|
|
98
|
+
[signerAddress]: output.signature
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
modifyAndSignTransactions: async (transactions) => {
|
|
104
|
+
const feature = requireFeature(
|
|
105
|
+
wallet,
|
|
106
|
+
SOLANA_SIGN_TRANSACTION
|
|
107
|
+
);
|
|
108
|
+
const encoder = _kit.getTransactionEncoder.call(void 0, );
|
|
109
|
+
const decoder = _kit.getTransactionDecoder.call(void 0, );
|
|
110
|
+
const outputs = await feature.signTransaction(
|
|
111
|
+
...transactions.map((tx) => ({
|
|
112
|
+
account,
|
|
113
|
+
transaction: new Uint8Array(encoder.encode(tx)),
|
|
114
|
+
chain
|
|
115
|
+
}))
|
|
116
|
+
);
|
|
117
|
+
return transactions.map((_tx, i) => {
|
|
118
|
+
const output = outputs[i];
|
|
119
|
+
if (!output)
|
|
120
|
+
throw new Error("[kheopskit] missing signTransaction output");
|
|
121
|
+
return decoder.decode(output.signedTransaction);
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
signAndSendTransactions: async (transactions) => {
|
|
125
|
+
const feature = requireFeature(
|
|
126
|
+
wallet,
|
|
127
|
+
SOLANA_SIGN_AND_SEND_TRANSACTION
|
|
128
|
+
);
|
|
129
|
+
const encoder = _kit.getTransactionEncoder.call(void 0, );
|
|
130
|
+
const outputs = await feature.signAndSendTransaction(
|
|
131
|
+
...transactions.map((tx) => ({
|
|
132
|
+
account,
|
|
133
|
+
transaction: new Uint8Array(encoder.encode(tx)),
|
|
134
|
+
chain
|
|
135
|
+
}))
|
|
136
|
+
);
|
|
137
|
+
return outputs.map((output) => output.signature);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
var createWalletConnectSolanaSigner = (provider, accountAddress, chain) => {
|
|
142
|
+
const signerAddress = _kit.address.call(void 0, accountAddress);
|
|
143
|
+
const request = (method, params) => {
|
|
144
|
+
if (!provider.session)
|
|
145
|
+
throw new (0, _chunkNU46D4MZjs.KheopskitError)("NO_SESSION", "No session found");
|
|
146
|
+
return provider.client.request({
|
|
147
|
+
topic: provider.session.topic,
|
|
148
|
+
chainId: getSolanaCaip2(chain),
|
|
149
|
+
request: { method, params }
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
return {
|
|
153
|
+
address: signerAddress,
|
|
154
|
+
modifyAndSignMessages: async (messages) => {
|
|
155
|
+
const toBase58 = _kit.getBase58Decoder.call(void 0, );
|
|
156
|
+
const fromBase58 = _kit.getBase58Encoder.call(void 0, );
|
|
157
|
+
return Promise.all(
|
|
158
|
+
messages.map(async (m) => {
|
|
159
|
+
const { signature } = await request(
|
|
160
|
+
"solana_signMessage",
|
|
161
|
+
{ pubkey: accountAddress, message: toBase58.decode(m.content) }
|
|
162
|
+
);
|
|
163
|
+
return {
|
|
164
|
+
content: m.content,
|
|
165
|
+
signatures: {
|
|
166
|
+
...m.signatures,
|
|
167
|
+
[signerAddress]: fromBase58.encode(signature)
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
})
|
|
171
|
+
);
|
|
172
|
+
},
|
|
173
|
+
modifyAndSignTransactions: async (transactions) => {
|
|
174
|
+
const encoder = _kit.getTransactionEncoder.call(void 0, );
|
|
175
|
+
const decoder = _kit.getTransactionDecoder.call(void 0, );
|
|
176
|
+
const toBase64 = _kit.getBase64Decoder.call(void 0, );
|
|
177
|
+
const fromBase64 = _kit.getBase64Encoder.call(void 0, );
|
|
178
|
+
const fromBase58 = _kit.getBase58Encoder.call(void 0, );
|
|
179
|
+
const signed = await Promise.all(
|
|
180
|
+
transactions.map(async (tx) => {
|
|
181
|
+
const result = await request("solana_signTransaction", {
|
|
182
|
+
transaction: toBase64.decode(encoder.encode(tx))
|
|
183
|
+
});
|
|
184
|
+
if (result.transaction)
|
|
185
|
+
return decoder.decode(fromBase64.encode(result.transaction));
|
|
186
|
+
if (result.signature)
|
|
187
|
+
return {
|
|
188
|
+
...tx,
|
|
189
|
+
signatures: {
|
|
190
|
+
...tx.signatures,
|
|
191
|
+
[signerAddress]: fromBase58.encode(
|
|
192
|
+
result.signature
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
throw new Error(
|
|
197
|
+
"[kheopskit] solana_signTransaction returned no transaction or signature"
|
|
198
|
+
);
|
|
199
|
+
})
|
|
200
|
+
);
|
|
201
|
+
return signed;
|
|
202
|
+
},
|
|
203
|
+
signAndSendTransactions: async (transactions) => {
|
|
204
|
+
const encoder = _kit.getTransactionEncoder.call(void 0, );
|
|
205
|
+
const toBase64 = _kit.getBase64Decoder.call(void 0, );
|
|
206
|
+
const fromBase58 = _kit.getBase58Encoder.call(void 0, );
|
|
207
|
+
return Promise.all(
|
|
208
|
+
transactions.map(async (tx) => {
|
|
209
|
+
const { signature } = await request(
|
|
210
|
+
"solana_signAndSendTransaction",
|
|
211
|
+
{ transaction: toBase64.decode(encoder.encode(tx)) }
|
|
212
|
+
);
|
|
213
|
+
return fromBase58.encode(signature);
|
|
214
|
+
})
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/api/solana/accounts.ts
|
|
221
|
+
var getInjectedWalletAccounts$ = (wallet, chain) => {
|
|
222
|
+
if (!wallet.isConnected) return _rxjs.of.call(void 0, []);
|
|
223
|
+
return _chunkSIUWQBT4js.getCachedObservable$.call(void 0,
|
|
224
|
+
`accounts:${wallet.id}:${chain}`,
|
|
225
|
+
() => new (0, _rxjs.Observable)((subscriber) => {
|
|
226
|
+
const standardWallet = wallet.wallet;
|
|
227
|
+
const buildAccounts = () => standardWallet.accounts.map(
|
|
228
|
+
(account) => ({
|
|
229
|
+
id: _chunkNU46D4MZjs.getWalletAccountId.call(void 0, wallet.id, account.address),
|
|
230
|
+
platform: "solana",
|
|
231
|
+
address: account.address,
|
|
232
|
+
chains: wallet.chains,
|
|
233
|
+
signer: createInjectedSolanaSigner(standardWallet, account, chain),
|
|
234
|
+
getSigner: (c) => createInjectedSolanaSigner(standardWallet, account, c),
|
|
235
|
+
walletName: wallet.name,
|
|
236
|
+
walletId: wallet.id
|
|
237
|
+
})
|
|
238
|
+
);
|
|
239
|
+
subscriber.next(buildAccounts());
|
|
240
|
+
const eventsFeature = standardWallet.features["standard:events"];
|
|
241
|
+
const off = _optionalChain([eventsFeature, 'optionalAccess', _ => _.on, 'call', _2 => _2(
|
|
242
|
+
"change",
|
|
243
|
+
() => subscriber.next(buildAccounts())
|
|
244
|
+
)]);
|
|
245
|
+
return () => {
|
|
246
|
+
_optionalChain([off, 'optionalCall', _3 => _3()]);
|
|
247
|
+
};
|
|
248
|
+
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }))
|
|
249
|
+
);
|
|
250
|
+
};
|
|
251
|
+
var getAppKitAccounts$ = (wallet, chain) => {
|
|
252
|
+
const provider = wallet.appKit.getProvider("solana");
|
|
253
|
+
if (!wallet.isConnected || !_optionalChain([provider, 'optionalAccess', _4 => _4.session])) return _rxjs.of.call(void 0, []);
|
|
254
|
+
return _chunkSIUWQBT4js.getCachedObservable$.call(void 0,
|
|
255
|
+
`accounts:${wallet.id}:${chain}`,
|
|
256
|
+
() => new (0, _rxjs.Observable)((subscriber) => {
|
|
257
|
+
const buildAccounts = () => {
|
|
258
|
+
const session = provider.session;
|
|
259
|
+
if (!session) return [];
|
|
260
|
+
const solanaCaip10s = Object.values(session.namespaces).flatMap((namespace) => _nullishCoalesce(namespace.accounts, () => ( []))).filter((account) => account.startsWith("solana:"));
|
|
261
|
+
const addresses = [
|
|
262
|
+
...new Set(
|
|
263
|
+
solanaCaip10s.map((account) => account.split(":")[2]).filter((address2) => !!address2)
|
|
264
|
+
)
|
|
265
|
+
];
|
|
266
|
+
const advertisedChains = [
|
|
267
|
+
...new Set(
|
|
268
|
+
solanaCaip10s.map((account) => account.split(":").slice(0, 2).join(":")).map(getSolanaChainIdFromCaip2).filter((c) => !!c)
|
|
269
|
+
)
|
|
270
|
+
];
|
|
271
|
+
const chains = advertisedChains.length ? advertisedChains : [chain];
|
|
272
|
+
return addresses.map(
|
|
273
|
+
(accountAddress) => ({
|
|
274
|
+
id: _chunkNU46D4MZjs.getWalletAccountId.call(void 0, wallet.id, accountAddress),
|
|
275
|
+
platform: "solana",
|
|
276
|
+
address: accountAddress,
|
|
277
|
+
chains,
|
|
278
|
+
signer: createWalletConnectSolanaSigner(
|
|
279
|
+
provider,
|
|
280
|
+
accountAddress,
|
|
281
|
+
chain
|
|
282
|
+
),
|
|
283
|
+
getSigner: (c) => createWalletConnectSolanaSigner(provider, accountAddress, c),
|
|
284
|
+
walletName: wallet.name,
|
|
285
|
+
walletId: wallet.id
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
};
|
|
289
|
+
subscriber.next(buildAccounts());
|
|
290
|
+
const reemit = () => subscriber.next(buildAccounts());
|
|
291
|
+
provider.on("session_update", reemit);
|
|
292
|
+
provider.on("accountsChanged", reemit);
|
|
293
|
+
return () => {
|
|
294
|
+
provider.off("session_update", reemit);
|
|
295
|
+
provider.off("accountsChanged", reemit);
|
|
296
|
+
};
|
|
297
|
+
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }))
|
|
298
|
+
);
|
|
299
|
+
};
|
|
300
|
+
var getSolanaAccounts$ = (solanaWallets$, solanaChain) => new (0, _rxjs.Observable)((subscriber) => {
|
|
301
|
+
const sub = solanaWallets$.pipe(
|
|
302
|
+
_rxjs.map.call(void 0, (wallets) => wallets.filter((w) => w.isConnected)),
|
|
303
|
+
_rxjs.switchMap.call(void 0,
|
|
304
|
+
(wallets) => wallets.length ? _rxjs.combineLatest.call(void 0, [
|
|
305
|
+
...wallets.filter((w) => w.type === "injected").map((w) => getInjectedWalletAccounts$(w, solanaChain)),
|
|
306
|
+
...wallets.filter((w) => w.type === "appKit").map((w) => getAppKitAccounts$(w, solanaChain))
|
|
307
|
+
]) : _rxjs.of.call(void 0, [])
|
|
308
|
+
),
|
|
309
|
+
_rxjs.map.call(void 0, (accounts) => accounts.flat()),
|
|
310
|
+
_rxjs.distinctUntilChanged.call(void 0, isSameAccountsList)
|
|
311
|
+
).subscribe(subscriber);
|
|
312
|
+
return () => {
|
|
313
|
+
sub.unsubscribe();
|
|
314
|
+
};
|
|
315
|
+
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
|
|
316
|
+
var isSameAccountsList = (a, b) => {
|
|
317
|
+
if (a.length !== b.length) return false;
|
|
318
|
+
return a.every((account, i) => {
|
|
319
|
+
const other = b[i];
|
|
320
|
+
if (!other || account.id !== other.id) return false;
|
|
321
|
+
if (account.chains.length !== other.chains.length) return false;
|
|
322
|
+
return account.chains.every((chain, j) => chain === other.chains[j]);
|
|
323
|
+
});
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// src/api/solana/wallets.ts
|
|
327
|
+
var _app = require('@wallet-standard/app');
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
var SOLANA_NAMESPACE_PREFIX = "solana:";
|
|
337
|
+
var isSolanaWallet = (wallet) => wallet.chains.some((chain) => chain.startsWith(SOLANA_NAMESPACE_PREFIX)) || Object.keys(wallet.features).some(
|
|
338
|
+
(feature) => feature.startsWith(SOLANA_NAMESPACE_PREFIX)
|
|
339
|
+
);
|
|
340
|
+
var getSolanaChains = (wallet) => wallet.chains.filter(
|
|
341
|
+
(chain) => isSolanaChainId(chain)
|
|
342
|
+
);
|
|
343
|
+
var walletStandardWallets$ = new (0, _rxjs.Observable)(
|
|
344
|
+
(subscriber) => {
|
|
345
|
+
if (typeof window === "undefined") {
|
|
346
|
+
subscriber.next([]);
|
|
347
|
+
return () => {
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
const { get, on } = _app.getWallets.call(void 0, );
|
|
351
|
+
const emit = () => subscriber.next(get().filter(isSolanaWallet));
|
|
352
|
+
emit();
|
|
353
|
+
const offRegister = on("register", emit);
|
|
354
|
+
const offUnregister = on("unregister", emit);
|
|
355
|
+
return () => {
|
|
356
|
+
offRegister();
|
|
357
|
+
offUnregister();
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
|
|
361
|
+
var createSolanaInjectedWallets$ = (store2) => new (0, _rxjs.Observable)((subscriber) => {
|
|
362
|
+
const enabledWalletIds$ = new (0, _rxjs.BehaviorSubject)(/* @__PURE__ */ new Set());
|
|
363
|
+
const connect = async (wallet, walletId) => {
|
|
364
|
+
if (enabledWalletIds$.value.has(walletId))
|
|
365
|
+
throw new (0, _chunkNU46D4MZjs.KheopskitError)(
|
|
366
|
+
"WALLET_ALREADY_CONNECTED",
|
|
367
|
+
`wallet ${walletId} is already connected`,
|
|
368
|
+
{ walletId }
|
|
369
|
+
);
|
|
370
|
+
const feature = wallet.features["standard:connect"];
|
|
371
|
+
if (!feature)
|
|
372
|
+
throw new (0, _chunkNU46D4MZjs.KheopskitError)(
|
|
373
|
+
"FEATURE_NOT_SUPPORTED",
|
|
374
|
+
`wallet ${walletId} does not support standard:connect`,
|
|
375
|
+
{ walletId }
|
|
376
|
+
);
|
|
377
|
+
await feature.connect();
|
|
378
|
+
const newSet = new Set(enabledWalletIds$.value);
|
|
379
|
+
newSet.add(walletId);
|
|
380
|
+
enabledWalletIds$.next(newSet);
|
|
381
|
+
store2.addEnabledWalletId(walletId);
|
|
382
|
+
};
|
|
383
|
+
const disconnect = async (wallet, walletId) => {
|
|
384
|
+
if (!enabledWalletIds$.value.has(walletId))
|
|
385
|
+
throw new (0, _chunkNU46D4MZjs.KheopskitError)(
|
|
386
|
+
"WALLET_NOT_CONNECTED",
|
|
387
|
+
`wallet ${walletId} is not connected`,
|
|
388
|
+
{ walletId }
|
|
389
|
+
);
|
|
390
|
+
const feature = wallet.features["standard:disconnect"];
|
|
391
|
+
await _optionalChain([feature, 'optionalAccess', _5 => _5.disconnect, 'call', _6 => _6()]);
|
|
392
|
+
const newSet = new Set(enabledWalletIds$.value);
|
|
393
|
+
newSet.delete(walletId);
|
|
394
|
+
enabledWalletIds$.next(newSet);
|
|
395
|
+
store2.removeEnabledWalletId(walletId);
|
|
396
|
+
_chunkSIUWQBT4js.clearCachedObservablesByPrefix.call(void 0, `accounts:${walletId}:`);
|
|
397
|
+
};
|
|
398
|
+
const sub = _rxjs.combineLatest.call(void 0, [walletStandardWallets$, enabledWalletIds$]).pipe(
|
|
399
|
+
_rxjs.map.call(void 0,
|
|
400
|
+
([wallets, enabledWalletIds]) => wallets.map((wallet) => {
|
|
401
|
+
const walletId = _chunkSIUWQBT4js.getWalletId.call(void 0, "solana", wallet.name);
|
|
402
|
+
return {
|
|
403
|
+
platform: "solana",
|
|
404
|
+
type: "injected",
|
|
405
|
+
id: walletId,
|
|
406
|
+
sourceId: wallet.name,
|
|
407
|
+
wallet,
|
|
408
|
+
chains: getSolanaChains(wallet),
|
|
409
|
+
name: wallet.name,
|
|
410
|
+
icon: wallet.icon,
|
|
411
|
+
isConnected: enabledWalletIds.has(walletId),
|
|
412
|
+
connect: () => connect(wallet, walletId),
|
|
413
|
+
disconnect: () => disconnect(wallet, walletId)
|
|
414
|
+
};
|
|
415
|
+
})
|
|
416
|
+
),
|
|
417
|
+
_rxjs.distinctUntilChanged.call(void 0, walletsEqual)
|
|
418
|
+
).subscribe(subscriber);
|
|
419
|
+
return () => {
|
|
420
|
+
sub.unsubscribe();
|
|
421
|
+
};
|
|
422
|
+
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
|
|
423
|
+
var getSolanaWallets$ = (config, store2 = _chunkNU46D4MZjs.store) => {
|
|
424
|
+
return new (0, _rxjs.Observable)((subscriber) => {
|
|
425
|
+
const subscription = _rxjs.combineLatest.call(void 0, [
|
|
426
|
+
createSolanaInjectedWallets$(store2),
|
|
427
|
+
_chunkNU46D4MZjs.getAppKitWallets$.call(void 0, config).pipe(_rxjs.map.call(void 0, (w) => w.solana))
|
|
428
|
+
]).pipe(
|
|
429
|
+
_rxjs.map.call(void 0,
|
|
430
|
+
([injectedWallets, appKitWallet]) => appKitWallet ? [...injectedWallets, appKitWallet] : injectedWallets
|
|
431
|
+
)
|
|
432
|
+
).subscribe(subscriber);
|
|
433
|
+
return () => {
|
|
434
|
+
subscription.unsubscribe();
|
|
435
|
+
};
|
|
436
|
+
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
|
|
437
|
+
};
|
|
438
|
+
var walletsEqual = (a, b) => {
|
|
439
|
+
if (a.length !== b.length) return false;
|
|
440
|
+
return a.every(
|
|
441
|
+
(w, i) => w.id === _optionalChain([b, 'access', _7 => _7[i], 'optionalAccess', _8 => _8.id]) && w.isConnected === _optionalChain([b, 'access', _9 => _9[i], 'optionalAccess', _10 => _10.isConnected]) && w.name === _optionalChain([b, 'access', _11 => _11[i], 'optionalAccess', _12 => _12.name])
|
|
442
|
+
);
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// src/api/solana/plugin.ts
|
|
446
|
+
var solana = (options = {}) => {
|
|
447
|
+
const chain = _nullishCoalesce(options.chain, () => ( DEFAULT_SOLANA_CHAIN));
|
|
448
|
+
if (!isSolanaChainId(chain)) {
|
|
449
|
+
console.warn(
|
|
450
|
+
`[kheopskit] Unknown solana chain: ${JSON.stringify(chain)}. Valid values: "solana:mainnet", "solana:devnet", "solana:testnet", "solana:localnet".`
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
return {
|
|
454
|
+
platform: "solana",
|
|
455
|
+
getWallets$: (ctx) => getSolanaWallets$(ctx.config, ctx.store),
|
|
456
|
+
getAccounts$: (wallets$) => getSolanaAccounts$(wallets$, chain)
|
|
457
|
+
};
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
exports.DEFAULT_SOLANA_CHAIN = DEFAULT_SOLANA_CHAIN; exports.getSolanaCaip2 = getSolanaCaip2; exports.isSolanaAddress = _chunkNU46D4MZjs.isSolanaAddress; exports.isSolanaChainId = isSolanaChainId; exports.solana = solana;
|
|
466
|
+
//# sourceMappingURL=solana.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/kheopskit/kheopskit/packages/core/dist/solana.js","../src/api/solana/chains.ts","../src/api/solana/accounts.ts","../src/api/solana/signer.ts","../src/api/solana/wallets.ts","../src/api/solana/plugin.ts"],"names":[],"mappings":"AAAA,gtBAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACF,sDAA4B;AAC5B;AACA;ACEO,IAAM,qBAAA,EAAsC,gBAAA;AAEnD,IAAM,iBAAA,EAAmB;AAAA,EACxB,gBAAA;AAAA,EACA,eAAA;AAAA,EACA,gBAAA;AAAA,EACA;AACD,CAAA;AAEO,IAAM,gBAAA,EAAkB,CAAC,KAAA,EAAA,GAC/B,OAAO,MAAA,IAAU,SAAA,GAChB,gBAAA,CAAuC,QAAA,CAAS,KAAK,CAAA;AAWvD,IAAM,sBAAA,EAAwB;AAAA,EAC7B,gBAAA,EAAkB,yCAAA;AAAA,EAClB,eAAA,EAAiB,yCAAA;AAAA,EACjB,gBAAA,EAAkB;AACnB,CAAA;AAQO,IAAM,eAAA,EAAiB,CAAC,KAAA,EAAA,GAAiC;AAC/D,EAAA,MAAM,MAAA,EAAS,qBAAA,CACd,KACD,CAAA;AACA,EAAA,GAAA,CAAI,CAAC,KAAA;AACJ,IAAA,MAAM,IAAI,oCAAA;AAAA,MACT,mBAAA;AAAA,MACA,CAAA,cAAA,EAAiB,KAAK,CAAA,mDAAA;AAAA,IACvB,CAAA;AACD,EAAA,OAAO,KAAA;AACR,CAAA;AAEA,IAAM,sBAAA,EAAuD,MAAA,CAAO,WAAA;AAAA,EACnE,MAAA,CAAO,OAAA,CAAQ,qBAAqB,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,KAAA,EAAO,KAAK,CAAA,EAAA,GAAM;AAAA,IAC7D,KAAA;AAAA,IACA;AAAA,EACD,CAAC;AACF,CAAA;AAMO,IAAM,0BAAA,EAA4B,CACxC,KAAA,EAAA,GAC+B,qBAAA,CAAsB,KAAK,CAAA;AD/B3D;AACA;AE5CA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AAAA,4BACM;AF8CP;AACA;AGxDA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AAAA,kCAIM;AAeP,IAAM,oBAAA,EAAsB,oBAAA;AAC5B,IAAM,wBAAA,EAA0B,wBAAA;AAChC,IAAM,iCAAA,EAAmC,+BAAA;AAazC,IAAM,eAAA,EAAiB,CAAI,MAAA,EAA8B,IAAA,EAAA,GAAoB;AAC5E,EAAA,MAAM,QAAA,EAAW,MAAA,CAAO,QAAA,CAAqC,IAAI,CAAA;AACjE,EAAA,GAAA,CAAI,CAAC,OAAA;AACJ,IAAA,MAAM,IAAI,oCAAA;AAAA,MACT,uBAAA;AAAA,MACA,CAAA,QAAA,EAAW,MAAA,CAAO,IAAI,CAAA,mBAAA,EAAsB,IAAI,CAAA;AAAA,IAAA;AAElD,EAAA;AACD;AASO;AAKN,EAAA;AAEA,EAAA;AAAO,IAAA;AACG,IAAA;AAER,MAAA;AAAgB,QAAA;AACf,QAAA;AACA,MAAA;AAED,MAAA;AAA8B,QAAA;AAC2B,MAAA;AAEzD,MAAA;AACC,QAAA;AACA,QAAA;AACA,QAAA;AAAO,UAAA;AACU,UAAA;AACJ,YAAA;AACN,YAAA;AACmB,UAAA;AACzB,QAAA;AACD,MAAA;AACA,IAAA;AACF,IAAA;AAEC,MAAA;AAAgB,QAAA;AACf,QAAA;AACA,MAAA;AAED,MAAA;AACA,MAAA;AACA,MAAA;AAA8B,QAAA;AACA,UAAA;AAC5B,UAAA;AAC8C,UAAA;AAC9C,QAAA;AACC,MAAA;AAEH,MAAA;AACC,QAAA;AACA,QAAA;AACC,UAAA;AACD,QAAA;AAA8C,MAAA;AAC9C,IAAA;AACF,IAAA;AAEC,MAAA;AAAgB,QAAA;AACf,QAAA;AACA,MAAA;AAED,MAAA;AACA,MAAA;AAA8B,QAAA;AACA,UAAA;AAC5B,UAAA;AAC8C,UAAA;AAC9C,QAAA;AACC,MAAA;AAEH,MAAA;AAAiE,IAAA;AAClE,EAAA;AAEF;AAUO;AAKN,EAAA;AAEA,EAAA;AACC,IAAA;AACC,MAAA;AAID,IAAA;AAAkC,MAAA;AACT,MAAA;AACK,MAAA;AACH,IAAA;AAC1B,EAAA;AAGF,EAAA;AAAO,IAAA;AACG,IAAA;AAKR,MAAA;AACA,MAAA;AACA,MAAA;AAAe,QAAA;AAEb,UAAA;AAA4B,YAAA;AAC3B,YAAA;AAC8D,UAAA;AAE/D,UAAA;AAAO,YAAA;AACK,YAAA;AACC,cAAA;AACN,cAAA;AACuC,YAAA;AAC7C,UAAA;AACD,QAAA;AACA,MAAA;AACF,IAAA;AACD,IAAA;AAEC,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AAA6B,QAAA;AAE3B,UAAA;AAG6B,YAAA;AACmB,UAAA;AAIhD,UAAA;AACC,YAAA;AACD,UAAA;AACC,YAAA;AAAO,cAAA;AACH,cAAA;AACS,gBAAA;AACL,gBAAA;AACsB,kBAAA;AACpB,gBAAA;AACR,cAAA;AACD,YAAA;AAEF,UAAA;AAAU,YAAA;AACT,UAAA;AACD,QAAA;AACA,MAAA;AAEF,MAAA;AAAO,IAAA;AACR,IAAA;AAEC,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AAAe,QAAA;AAEb,UAAA;AAA4B,YAAA;AAC3B,YAAA;AACmD,UAAA;AAEpD,UAAA;AAAkC,QAAA;AAClC,MAAA;AACF,IAAA;AACD,EAAA;AAEF;AHVA;AACA;AEjMA;AAIC,EAAA;AAEA,EAAA;AAAO,IAAA;AAAmD,IAAA;AAExD,MAAA;AAEA,MAAA;AACyB,QAAA;AACM,UAAA;AACqB,UAAA;AACvC,UAAA;AACO,UAAA;AACF,UAAA;AACkD,UAAA;AAEX,UAAA;AACnC,UAAA;AACF,QAAA;AAClB,MAAA;AAGF,MAAA;AAGA,MAAA;AAGA,MAAA;AAA2B,QAAA;AAAG,QAAA;AACE,MAAA;AAGhC,MAAA;AACC,wBAAA;AAAM,MAAA;AACP,IAAA;AACqD,EAAA;AAExD;AAEA;AAIC,EAAA;AAEA,EAAA;AAEA,EAAA;AAAO,IAAA;AAAmD,IAAA;AAMxD,MAAA;AACC,QAAA;AACA,QAAA;AAEA,QAAA;AAIA,QAAA;AAAkB,UAAA;AACV,YAAA;AAG4C,UAAA;AACnD,QAAA;AAMD,QAAA;AAAyB,UAAA;AACjB,YAAA;AAIiC,UAAA;AACxC,QAAA;AAED,QAAA;AAEA,QAAA;AAAiB,UAAA;AACoB,YAAA;AACa,YAAA;AACtC,YAAA;AACD,YAAA;AACT,YAAA;AACQ,cAAA;AACP,cAAA;AACA,cAAA;AACA,YAAA;AACD,YAAA;AAE4D,YAAA;AACzC,YAAA;AACF,UAAA;AAClB,QAAA;AACD,MAAA;AAGD,MAAA;AAIA,MAAA;AACA,MAAA;AACA,MAAA;AAEA,MAAA;AACC,QAAA;AACA,QAAA;AAAsC,MAAA;AACvC,IAAA;AACqD,EAAA;AAExD;AAEO;AAKL,EAAA;AACE,IAAA;AACqD,IAAA;AACrD,MAAA;AAEkB,QAAA;AAGyC,QAAA;AAGR,MAAA;AAE1C,IAAA;AACT,IAAA;AACiC,IAAA;AACM,EAAA;AAIzC,EAAA;AACC,IAAA;AAAgB,EAAA;AAElB;AAED;AACC,EAAA;AACA,EAAA;AACC,IAAA;AACA,IAAA;AAEA,IAAA;AACA,IAAA;AAAmE,EAAA;AAErE;AF2IA;AACA;AIrUA;AAMA;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AAcD;AAGA;AAE8B,EAAA;AAE7B;AAED;AACe,EAAA;AAEd;AAMD;AAAmC,EAAA;AAGjC,IAAA;AACC,MAAA;AACA,MAAA;AAAa,MAAA;AAAC,IAAA;AAGf,IAAA;AACA,IAAA;AAEA,IAAA;AAEA,IAAA;AACA,IAAA;AAEA,IAAA;AACC,MAAA;AACA,MAAA;AAAc,IAAA;AACf,EAAA;AAEF;AAEA;AAEE,EAAA;AAEA,EAAA;AAIC,IAAA;AACC,MAAA;AAAU,QAAA;AACT,QAAA;AACkB,QAAA;AACP,MAAA;AAGb,IAAA;AAGA,IAAA;AACC,MAAA;AAAU,QAAA;AACT,QAAA;AACkB,QAAA;AACP,MAAA;AAGb,IAAA;AAEA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AAAiC,EAAA;AAGlC,EAAA;AAIC,IAAA;AACC,MAAA;AAAU,QAAA;AACT,QAAA;AACkB,QAAA;AACP,MAAA;AAMb,IAAA;AAGA,IAAA;AAEA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AAIA,IAAA;AAAsD,EAAA;AAGvD,EAAA;AACE,IAAA;AACA,MAAA;AAEE,QAAA;AAEA,QAAA;AAAO,UAAA;AACI,UAAA;AACJ,UAAA;AACF,UAAA;AACa,UAAA;AACjB,UAAA;AAC8B,UAAA;AACjB,UAAA;AACA,UAAA;AAC6B,UAAA;AACH,UAAA;AACM,QAAA;AAC9C,MAAA;AACA,IAAA;AACF,IAAA;AACiC,EAAA;AAInC,EAAA;AACC,IAAA;AAAgB,EAAA;AAElB;AAEM;AAIN,EAAA;AACC,IAAA;AAAmC,MAAA;AACA,MAAA;AACiB,IAAA;AAElD,MAAA;AACA,QAAA;AACqD,MAAA;AACrD,IAAA;AAIF,IAAA;AACC,MAAA;AAAyB,IAAA;AAC1B,EAAA;AAEF;AAKA;AAIC,EAAA;AACA,EAAA;AAAS,IAAA;AAIU,EAAA;AAEpB;AJsPA;AACA;AK/ZO;AAGN,EAAA;AAEA,EAAA;AACC,IAAA;AAAQ,MAAA;AACmD,IAAA;AAC3D,EAAA;AAGD,EAAA;AAAO,IAAA;AACI,IAAA;AAE8B,IAAA;AACsB,EAAA;AAEhE;AL4ZA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/kheopskit/kheopskit/packages/core/dist/solana.js","sourcesContent":[null,"import { KheopskitError } from \"../errors\";\n\n/**\n * Wallet Standard chain identifiers for Solana clusters.\n *\n * These are the values wallets advertise in their `chains` arrays and the\n * values kheopskit accepts in `config.solanaChain`.\n *\n * @see https://github.com/anza-xyz/wallet-standard\n */\nexport type SolanaChainId =\n\t| \"solana:mainnet\"\n\t| \"solana:devnet\"\n\t| \"solana:testnet\"\n\t| \"solana:localnet\";\n\nexport const DEFAULT_SOLANA_CHAIN: SolanaChainId = \"solana:mainnet\";\n\nconst SOLANA_CHAIN_IDS = [\n\t\"solana:mainnet\",\n\t\"solana:devnet\",\n\t\"solana:testnet\",\n\t\"solana:localnet\",\n] as const satisfies SolanaChainId[];\n\nexport const isSolanaChainId = (value: unknown): value is SolanaChainId =>\n\ttypeof value === \"string\" &&\n\t(SOLANA_CHAIN_IDS as readonly string[]).includes(value);\n\n/**\n * Maps Wallet Standard chain ids to the CAIP-2 chain ids used by WalletConnect.\n *\n * CAIP-2 ids use the first 32 characters of the cluster's genesis hash as the\n * reference. The values below match `@reown/appkit/networks` (solana,\n * solanaDevnet, solanaTestnet), which is what AppKit puts in session namespaces.\n *\n * `localnet` has no canonical CAIP-2 id and cannot be used over WalletConnect.\n */\nconst SOLANA_CHAIN_TO_CAIP2 = {\n\t\"solana:mainnet\": \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\",\n\t\"solana:devnet\": \"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1\",\n\t\"solana:testnet\": \"solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z\",\n} as const satisfies Partial<Record<SolanaChainId, string>>;\n\n/**\n * Returns the CAIP-2 chain id for a Solana chain, for use in WalletConnect\n * requests and when reading WalletConnect session namespaces.\n *\n * @throws if the chain has no canonical CAIP-2 id (e.g. localnet)\n */\nexport const getSolanaCaip2 = (chain: SolanaChainId): string => {\n\tconst caip2 = (SOLANA_CHAIN_TO_CAIP2 as Record<string, string | undefined>)[\n\t\tchain\n\t];\n\tif (!caip2)\n\t\tthrow new KheopskitError(\n\t\t\t\"UNSUPPORTED_CHAIN\",\n\t\t\t`Solana chain \"${chain}\" cannot be used over WalletConnect (no CAIP-2 id).`,\n\t\t);\n\treturn caip2;\n};\n\nconst CAIP2_TO_SOLANA_CHAIN: Record<string, SolanaChainId> = Object.fromEntries(\n\tObject.entries(SOLANA_CHAIN_TO_CAIP2).map(([chain, caip2]) => [\n\t\tcaip2,\n\t\tchain as SolanaChainId,\n\t]),\n);\n\n/**\n * Maps a CAIP-2 chain id (as found in WalletConnect session namespaces) back to\n * its {@link SolanaChainId}, or `undefined` if it isn't a recognised cluster.\n */\nexport const getSolanaChainIdFromCaip2 = (\n\tcaip2: string,\n): SolanaChainId | undefined => CAIP2_TO_SOLANA_CHAIN[caip2];\n","import type { StandardEventsFeature } from \"@wallet-standard/features\";\nimport {\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tObservable,\n\tof,\n\tshareReplay,\n\tswitchMap,\n} from \"rxjs\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { getCachedObservable$ } from \"../../utils/getCachedObservable\";\nimport type { SolanaAppKitWallet } from \"../types\";\nimport { getSolanaChainIdFromCaip2, type SolanaChainId } from \"./chains\";\nimport {\n\tcreateInjectedSolanaSigner,\n\tcreateWalletConnectSolanaSigner,\n} from \"./signer\";\nimport type {\n\tSolanaAccount,\n\tSolanaInjectedWallet,\n\tSolanaWallet,\n} from \"./types\";\n\ntype StandardEventsApi = StandardEventsFeature[\"standard:events\"];\n\nconst getInjectedWalletAccounts$ = (\n\twallet: SolanaInjectedWallet,\n\tchain: SolanaChainId,\n): Observable<SolanaAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn getCachedObservable$(`accounts:${wallet.id}:${chain}`, () =>\n\t\tnew Observable<SolanaAccount[]>((subscriber) => {\n\t\t\tconst standardWallet = wallet.wallet;\n\n\t\t\tconst buildAccounts = (): SolanaAccount[] =>\n\t\t\t\tstandardWallet.accounts.map(\n\t\t\t\t\t(account): SolanaAccount => ({\n\t\t\t\t\t\tid: getWalletAccountId(wallet.id, account.address),\n\t\t\t\t\t\tplatform: \"solana\",\n\t\t\t\t\t\taddress: account.address,\n\t\t\t\t\t\tchains: wallet.chains,\n\t\t\t\t\t\tsigner: createInjectedSolanaSigner(standardWallet, account, chain),\n\t\t\t\t\t\tgetSigner: (c) =>\n\t\t\t\t\t\t\tcreateInjectedSolanaSigner(standardWallet, account, c),\n\t\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\tsubscriber.next(buildAccounts());\n\n\t\t\t// Re-emit when the wallet's authorized accounts change.\n\t\t\tconst eventsFeature = (\n\t\t\t\tstandardWallet.features as Record<string, unknown>\n\t\t\t)[\"standard:events\"] as StandardEventsApi | undefined;\n\t\t\tconst off = eventsFeature?.on(\"change\", () =>\n\t\t\t\tsubscriber.next(buildAccounts()),\n\t\t\t);\n\n\t\t\treturn () => {\n\t\t\t\toff?.();\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n\nconst getAppKitAccounts$ = (\n\twallet: SolanaAppKitWallet,\n\tchain: SolanaChainId,\n): Observable<SolanaAccount[]> => {\n\tconst provider = wallet.appKit.getProvider(\"solana\");\n\n\tif (!wallet.isConnected || !provider?.session) return of([]);\n\n\treturn getCachedObservable$(`accounts:${wallet.id}:${chain}`, () =>\n\t\tnew Observable<SolanaAccount[]>((subscriber) => {\n\t\t\t// AppKit has no native solana adapter, so getAccount(\"solana\").allAccounts\n\t\t\t// is always empty; the WalletConnect session is the source of truth.\n\t\t\t// Accounts are CAIP-10 strings (\"solana:<chainRef>:<address>\"), one entry\n\t\t\t// per chain, so dedupe to unique addresses.\n\t\t\tconst buildAccounts = (): SolanaAccount[] => {\n\t\t\t\tconst session = provider.session;\n\t\t\t\tif (!session) return [];\n\n\t\t\t\tconst solanaCaip10s = Object.values(session.namespaces)\n\t\t\t\t\t.flatMap((namespace) => namespace.accounts ?? [])\n\t\t\t\t\t.filter((account) => account.startsWith(\"solana:\"));\n\n\t\t\t\tconst addresses = [\n\t\t\t\t\t...new Set(\n\t\t\t\t\t\tsolanaCaip10s\n\t\t\t\t\t\t\t.map((account) => account.split(\":\")[2])\n\t\t\t\t\t\t\t.filter((address): address is string => !!address),\n\t\t\t\t\t),\n\t\t\t\t];\n\n\t\t\t\t// Clusters the session actually advertises (\"solana:<chainRef>\" from\n\t\t\t\t// each CAIP-10 entry), mapped back to SolanaChainId. Falls back to the\n\t\t\t\t// configured chain when none are recognised.\n\t\t\t\tconst advertisedChains = [\n\t\t\t\t\t...new Set(\n\t\t\t\t\t\tsolanaCaip10s\n\t\t\t\t\t\t\t.map((account) => account.split(\":\").slice(0, 2).join(\":\"))\n\t\t\t\t\t\t\t.map(getSolanaChainIdFromCaip2)\n\t\t\t\t\t\t\t.filter((c): c is SolanaChainId => !!c),\n\t\t\t\t\t),\n\t\t\t\t];\n\t\t\t\tconst chains = advertisedChains.length ? advertisedChains : [chain];\n\n\t\t\t\treturn addresses.map(\n\t\t\t\t\t(accountAddress): SolanaAccount => ({\n\t\t\t\t\t\tid: getWalletAccountId(wallet.id, accountAddress),\n\t\t\t\t\t\tplatform: \"solana\",\n\t\t\t\t\t\taddress: accountAddress,\n\t\t\t\t\t\tchains,\n\t\t\t\t\t\tsigner: createWalletConnectSolanaSigner(\n\t\t\t\t\t\t\tprovider,\n\t\t\t\t\t\t\taccountAddress,\n\t\t\t\t\t\t\tchain,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tgetSigner: (c) =>\n\t\t\t\t\t\t\tcreateWalletConnectSolanaSigner(provider, accountAddress, c),\n\t\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t};\n\n\t\t\tsubscriber.next(buildAccounts());\n\n\t\t\t// Re-derive when the WalletConnect session's accounts change, mirroring\n\t\t\t// the injected wallet's standard:events \"change\" subscription.\n\t\t\tconst reemit = () => subscriber.next(buildAccounts());\n\t\t\tprovider.on(\"session_update\", reemit);\n\t\t\tprovider.on(\"accountsChanged\", reemit);\n\n\t\t\treturn () => {\n\t\t\t\tprovider.off(\"session_update\", reemit);\n\t\t\t\tprovider.off(\"accountsChanged\", reemit);\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n\nexport const getSolanaAccounts$ = (\n\tsolanaWallets$: Observable<SolanaWallet[]>,\n\tsolanaChain: SolanaChainId,\n) =>\n\tnew Observable<SolanaAccount[]>((subscriber) => {\n\t\tconst sub = solanaWallets$\n\t\t\t.pipe(\n\t\t\t\tmap((wallets) => wallets.filter((w) => w.isConnected)),\n\t\t\t\tswitchMap((wallets) =>\n\t\t\t\t\twallets.length\n\t\t\t\t\t\t? combineLatest([\n\t\t\t\t\t\t\t\t...wallets\n\t\t\t\t\t\t\t\t\t.filter((w) => w.type === \"injected\")\n\t\t\t\t\t\t\t\t\t.map((w) => getInjectedWalletAccounts$(w, solanaChain)),\n\t\t\t\t\t\t\t\t...wallets\n\t\t\t\t\t\t\t\t\t.filter((w) => w.type === \"appKit\")\n\t\t\t\t\t\t\t\t\t.map((w) => getAppKitAccounts$(w, solanaChain)),\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t: of([]),\n\t\t\t\t),\n\t\t\t\tmap((accounts) => accounts.flat()),\n\t\t\t\tdistinctUntilChanged(isSameAccountsList),\n\t\t\t)\n\t\t\t.subscribe(subscriber);\n\n\t\treturn () => {\n\t\t\tsub.unsubscribe();\n\t\t};\n\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n\nconst isSameAccountsList = (a: SolanaAccount[], b: SolanaAccount[]) => {\n\tif (a.length !== b.length) return false;\n\treturn a.every((account, i) => {\n\t\tconst other = b[i];\n\t\tif (!other || account.id !== other.id) return false;\n\t\t// Re-emit when the advertised clusters change, not just on id changes.\n\t\tif (account.chains.length !== other.chains.length) return false;\n\t\treturn account.chains.every((chain, j) => chain === other.chains[j]);\n\t});\n};\n","import {\n\taddress,\n\tgetBase58Decoder,\n\tgetBase58Encoder,\n\tgetBase64Decoder,\n\tgetBase64Encoder,\n\tgetTransactionDecoder,\n\tgetTransactionEncoder,\n\ttype SignableMessage,\n\ttype SignatureBytes,\n\ttype TransactionModifyingSigner,\n} from \"@solana/kit\";\nimport type {\n\tSolanaSignAndSendTransactionFeature,\n\tSolanaSignMessageFeature,\n\tSolanaSignTransactionFeature,\n} from \"@solana/wallet-standard-features\";\nimport type {\n\tWalletAccount,\n\tWallet as WalletStandardWallet,\n} from \"@wallet-standard/base\";\nimport { KheopskitError } from \"../errors\";\nimport type { WalletConnectProvider } from \"../types\";\nimport { getSolanaCaip2, type SolanaChainId } from \"./chains\";\nimport type { SolanaSigner } from \"./types\";\n\nconst SOLANA_SIGN_MESSAGE = \"solana:signMessage\";\nconst SOLANA_SIGN_TRANSACTION = \"solana:signTransaction\";\nconst SOLANA_SIGN_AND_SEND_TRANSACTION = \"solana:signAndSendTransaction\";\n\ntype SignMessageApi = SolanaSignMessageFeature[typeof SOLANA_SIGN_MESSAGE];\ntype SignTransactionApi =\n\tSolanaSignTransactionFeature[typeof SOLANA_SIGN_TRANSACTION];\ntype SignAndSendApi =\n\tSolanaSignAndSendTransactionFeature[typeof SOLANA_SIGN_AND_SEND_TRANSACTION];\n\n/** The branded array type expected back from a transaction-modifying signer. */\ntype SignedTransactions = Awaited<\n\tReturnType<TransactionModifyingSigner[\"modifyAndSignTransactions\"]>\n>;\n\nconst requireFeature = <T>(wallet: WalletStandardWallet, name: string): T => {\n\tconst feature = (wallet.features as Record<string, unknown>)[name];\n\tif (!feature)\n\t\tthrow new KheopskitError(\n\t\t\t\"FEATURE_NOT_SUPPORTED\",\n\t\t\t`wallet \"${wallet.name}\" does not support ${name}`,\n\t\t);\n\treturn feature as T;\n};\n\n/**\n * Builds a {@link SolanaSigner} backed by a Wallet Standard wallet's\n * `solana:*` features (injected wallets).\n *\n * Transactions are exchanged as wire bytes; messages and signatures as raw\n * bytes. Calling a method whose feature the wallet does not advertise throws.\n */\nexport const createInjectedSolanaSigner = (\n\twallet: WalletStandardWallet,\n\taccount: WalletAccount,\n\tchain: SolanaChainId,\n): SolanaSigner => {\n\tconst signerAddress = address(account.address);\n\n\treturn {\n\t\taddress: signerAddress,\n\t\tmodifyAndSignMessages: async (messages) => {\n\t\t\tconst feature = requireFeature<SignMessageApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_MESSAGE,\n\t\t\t);\n\t\t\tconst outputs = await feature.signMessage(\n\t\t\t\t...messages.map((m) => ({ account, message: m.content })),\n\t\t\t);\n\t\t\treturn messages.map((m, i) => {\n\t\t\t\tconst output = outputs[i];\n\t\t\t\tif (!output) throw new Error(\"[kheopskit] missing signMessage output\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: output.signedMessage,\n\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t...m.signatures,\n\t\t\t\t\t\t[signerAddress]: output.signature as SignatureBytes,\n\t\t\t\t\t},\n\t\t\t\t} satisfies SignableMessage;\n\t\t\t});\n\t\t},\n\t\tmodifyAndSignTransactions: async (transactions) => {\n\t\t\tconst feature = requireFeature<SignTransactionApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_TRANSACTION,\n\t\t\t);\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst decoder = getTransactionDecoder();\n\t\t\tconst outputs = await feature.signTransaction(\n\t\t\t\t...transactions.map((tx) => ({\n\t\t\t\t\taccount,\n\t\t\t\t\ttransaction: new Uint8Array(encoder.encode(tx)),\n\t\t\t\t\tchain,\n\t\t\t\t})),\n\t\t\t);\n\t\t\treturn transactions.map((_tx, i) => {\n\t\t\t\tconst output = outputs[i];\n\t\t\t\tif (!output)\n\t\t\t\t\tthrow new Error(\"[kheopskit] missing signTransaction output\");\n\t\t\t\treturn decoder.decode(output.signedTransaction);\n\t\t\t}) as unknown as SignedTransactions;\n\t\t},\n\t\tsignAndSendTransactions: async (transactions) => {\n\t\t\tconst feature = requireFeature<SignAndSendApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_AND_SEND_TRANSACTION,\n\t\t\t);\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst outputs = await feature.signAndSendTransaction(\n\t\t\t\t...transactions.map((tx) => ({\n\t\t\t\t\taccount,\n\t\t\t\t\ttransaction: new Uint8Array(encoder.encode(tx)),\n\t\t\t\t\tchain,\n\t\t\t\t})),\n\t\t\t);\n\t\t\treturn outputs.map((output) => output.signature as SignatureBytes);\n\t\t},\n\t};\n};\n\n/**\n * Builds a {@link SolanaSigner} backed by a WalletConnect session, adapting the\n * `solana_*` RPC methods to the same interface as the injected signer.\n *\n * The CAIP-2 chain id is derived from {@link SolanaChainId}; transactions are\n * base64-encoded and messages/signatures base58-encoded, per the WalletConnect\n * Solana spec.\n */\nexport const createWalletConnectSolanaSigner = (\n\tprovider: WalletConnectProvider,\n\taccountAddress: string,\n\tchain: SolanaChainId,\n): SolanaSigner => {\n\tconst signerAddress = address(accountAddress);\n\n\tconst request = <T>(method: string, params: unknown): Promise<T> => {\n\t\tif (!provider.session)\n\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\t\t// Resolved lazily (not at signer construction) so building a signer for a\n\t\t// cluster without a CAIP-2 id (e.g. localnet) doesn't throw until a request\n\t\t// is actually attempted.\n\t\treturn provider.client.request<T>({\n\t\t\ttopic: provider.session.topic,\n\t\t\tchainId: getSolanaCaip2(chain),\n\t\t\trequest: { method, params },\n\t\t});\n\t};\n\n\treturn {\n\t\taddress: signerAddress,\n\t\tmodifyAndSignMessages: async (messages) => {\n\t\t\t// @solana/kit naming is the inverse of the value direction here: a\n\t\t\t// Decoder turns bytes -> string (so `toBase58` produces a base58 string),\n\t\t\t// an Encoder turns string -> bytes (so `fromBase58` parses one).\n\t\t\tconst toBase58 = getBase58Decoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\treturn Promise.all(\n\t\t\t\tmessages.map(async (m) => {\n\t\t\t\t\tconst { signature } = await request<{ signature: string }>(\n\t\t\t\t\t\t\"solana_signMessage\",\n\t\t\t\t\t\t{ pubkey: accountAddress, message: toBase58.decode(m.content) },\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: m.content,\n\t\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t\t...m.signatures,\n\t\t\t\t\t\t\t[signerAddress]: fromBase58.encode(signature) as SignatureBytes,\n\t\t\t\t\t\t},\n\t\t\t\t\t} satisfies SignableMessage;\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t\tmodifyAndSignTransactions: async (transactions) => {\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst decoder = getTransactionDecoder();\n\t\t\tconst toBase64 = getBase64Decoder();\n\t\t\tconst fromBase64 = getBase64Encoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\tconst signed = await Promise.all(\n\t\t\t\ttransactions.map(async (tx) => {\n\t\t\t\t\tconst result = await request<{\n\t\t\t\t\t\ttransaction?: string;\n\t\t\t\t\t\tsignature?: string;\n\t\t\t\t\t}>(\"solana_signTransaction\", {\n\t\t\t\t\t\ttransaction: toBase64.decode(encoder.encode(tx)),\n\t\t\t\t\t});\n\t\t\t\t\t// Wallets may return either the full signed transaction (base64)\n\t\t\t\t\t// or just the signature (base58) to merge into the original.\n\t\t\t\t\tif (result.transaction)\n\t\t\t\t\t\treturn decoder.decode(fromBase64.encode(result.transaction));\n\t\t\t\t\tif (result.signature)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...tx,\n\t\t\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t\t\t...tx.signatures,\n\t\t\t\t\t\t\t\t[signerAddress]: fromBase58.encode(\n\t\t\t\t\t\t\t\t\tresult.signature,\n\t\t\t\t\t\t\t\t) as SignatureBytes,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"[kheopskit] solana_signTransaction returned no transaction or signature\",\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn signed as unknown as SignedTransactions;\n\t\t},\n\t\tsignAndSendTransactions: async (transactions) => {\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst toBase64 = getBase64Decoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\treturn Promise.all(\n\t\t\t\ttransactions.map(async (tx) => {\n\t\t\t\t\tconst { signature } = await request<{ signature: string }>(\n\t\t\t\t\t\t\"solana_signAndSendTransaction\",\n\t\t\t\t\t\t{ transaction: toBase64.decode(encoder.encode(tx)) },\n\t\t\t\t\t);\n\t\t\t\t\treturn fromBase58.encode(signature) as SignatureBytes;\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t};\n};\n","import { getWallets } from \"@wallet-standard/app\";\nimport type { Wallet as WalletStandardWallet } from \"@wallet-standard/base\";\nimport type {\n\tStandardConnectFeature,\n\tStandardDisconnectFeature,\n} from \"@wallet-standard/features\";\nimport {\n\tBehaviorSubject,\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tObservable,\n\tshareReplay,\n} from \"rxjs\";\nimport { clearCachedObservablesByPrefix } from \"../../utils/getCachedObservable\";\nimport { getWalletId, type WalletId } from \"../../utils/WalletId\";\nimport { getAppKitWallets$ } from \"../appKit\";\nimport { KheopskitError } from \"../errors\";\nimport { store as defaultStore, type KheopskitStore } from \"../store\";\nimport type { KheopskitConfig } from \"../types\";\nimport { isSolanaChainId, type SolanaChainId } from \"./chains\";\nimport type { SolanaInjectedWallet, SolanaWallet } from \"./types\";\n\ntype ConnectApi = StandardConnectFeature[\"standard:connect\"];\ntype DisconnectApi = StandardDisconnectFeature[\"standard:disconnect\"];\n\nconst SOLANA_NAMESPACE_PREFIX = \"solana:\";\n\n/** A Wallet Standard wallet is Solana-capable if it advertises a solana chain or feature. */\nconst isSolanaWallet = (wallet: WalletStandardWallet): boolean =>\n\twallet.chains.some((chain) => chain.startsWith(SOLANA_NAMESPACE_PREFIX)) ||\n\tObject.keys(wallet.features).some((feature) =>\n\t\tfeature.startsWith(SOLANA_NAMESPACE_PREFIX),\n\t);\n\nconst getSolanaChains = (wallet: WalletStandardWallet): SolanaChainId[] =>\n\twallet.chains.filter((chain): chain is SolanaChainId =>\n\t\tisSolanaChainId(chain),\n\t);\n\n/**\n * Observable of Solana-capable Wallet Standard wallets, updated as wallets\n * register/unregister. Returns an empty array during SSR.\n */\nconst walletStandardWallets$ = new Observable<readonly WalletStandardWallet[]>(\n\t(subscriber) => {\n\t\t// Guard against SSR - the Wallet Standard registry requires browser APIs\n\t\tif (typeof window === \"undefined\") {\n\t\t\tsubscriber.next([]);\n\t\t\treturn () => {};\n\t\t}\n\n\t\tconst { get, on } = getWallets();\n\t\tconst emit = () => subscriber.next(get().filter(isSolanaWallet));\n\n\t\temit();\n\n\t\tconst offRegister = on(\"register\", emit);\n\t\tconst offUnregister = on(\"unregister\", emit);\n\n\t\treturn () => {\n\t\t\toffRegister();\n\t\t\toffUnregister();\n\t\t};\n\t},\n).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n\nconst createSolanaInjectedWallets$ = (store: KheopskitStore) =>\n\tnew Observable<SolanaInjectedWallet[]>((subscriber) => {\n\t\tconst enabledWalletIds$ = new BehaviorSubject<Set<WalletId>>(new Set());\n\n\t\tconst connect = async (\n\t\t\twallet: WalletStandardWallet,\n\t\t\twalletId: WalletId,\n\t\t) => {\n\t\t\tif (enabledWalletIds$.value.has(walletId))\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"WALLET_ALREADY_CONNECTED\",\n\t\t\t\t\t`wallet ${walletId} is already connected`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\n\t\t\tconst feature = (wallet.features as Record<string, unknown>)[\n\t\t\t\t\"standard:connect\"\n\t\t\t] as ConnectApi | undefined;\n\t\t\tif (!feature)\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"FEATURE_NOT_SUPPORTED\",\n\t\t\t\t\t`wallet ${walletId} does not support standard:connect`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\n\t\t\tawait feature.connect();\n\n\t\t\tconst newSet = new Set(enabledWalletIds$.value);\n\t\t\tnewSet.add(walletId);\n\t\t\tenabledWalletIds$.next(newSet);\n\n\t\t\tstore.addEnabledWalletId(walletId);\n\t\t};\n\n\t\tconst disconnect = async (\n\t\t\twallet: WalletStandardWallet,\n\t\t\twalletId: WalletId,\n\t\t) => {\n\t\t\tif (!enabledWalletIds$.value.has(walletId))\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"WALLET_NOT_CONNECTED\",\n\t\t\t\t\t`wallet ${walletId} is not connected`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\n\t\t\t// standard:disconnect is an optional feature. Await it when present so a\n\t\t\t// failed disconnect rejects the returned promise; if absent we still\n\t\t\t// clear local state below.\n\t\t\tconst feature = (wallet.features as Record<string, unknown>)[\n\t\t\t\t\"standard:disconnect\"\n\t\t\t] as DisconnectApi | undefined;\n\t\t\tawait feature?.disconnect();\n\n\t\t\tconst newSet = new Set(enabledWalletIds$.value);\n\t\t\tnewSet.delete(walletId);\n\t\t\tenabledWalletIds$.next(newSet);\n\n\t\t\tstore.removeEnabledWalletId(walletId);\n\n\t\t\t// Drop cached account observables for this wallet so a later reconnect\n\t\t\t// rebuilds them against the current wallet handle, not a stale closure.\n\t\t\tclearCachedObservablesByPrefix(`accounts:${walletId}:`);\n\t\t};\n\n\t\tconst sub = combineLatest([walletStandardWallets$, enabledWalletIds$])\n\t\t\t.pipe(\n\t\t\t\tmap(([wallets, enabledWalletIds]) =>\n\t\t\t\t\twallets.map((wallet): SolanaInjectedWallet => {\n\t\t\t\t\t\tconst walletId = getWalletId(\"solana\", wallet.name);\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tplatform: \"solana\",\n\t\t\t\t\t\t\ttype: \"injected\",\n\t\t\t\t\t\t\tid: walletId,\n\t\t\t\t\t\t\tsourceId: wallet.name,\n\t\t\t\t\t\t\twallet,\n\t\t\t\t\t\t\tchains: getSolanaChains(wallet),\n\t\t\t\t\t\t\tname: wallet.name,\n\t\t\t\t\t\t\ticon: wallet.icon,\n\t\t\t\t\t\t\tisConnected: enabledWalletIds.has(walletId),\n\t\t\t\t\t\t\tconnect: () => connect(wallet, walletId),\n\t\t\t\t\t\t\tdisconnect: () => disconnect(wallet, walletId),\n\t\t\t\t\t\t};\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\tdistinctUntilChanged(walletsEqual),\n\t\t\t)\n\t\t\t.subscribe(subscriber);\n\n\t\treturn () => {\n\t\t\tsub.unsubscribe();\n\t\t};\n\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n\nexport const getSolanaWallets$ = (\n\tconfig: KheopskitConfig,\n\tstore: KheopskitStore = defaultStore,\n) => {\n\treturn new Observable<SolanaWallet[]>((subscriber) => {\n\t\tconst subscription = combineLatest([\n\t\t\tcreateSolanaInjectedWallets$(store),\n\t\t\tgetAppKitWallets$(config).pipe(map((w) => w.solana)),\n\t\t])\n\t\t\t.pipe(\n\t\t\t\tmap(([injectedWallets, appKitWallet]) =>\n\t\t\t\t\tappKitWallet ? [...injectedWallets, appKitWallet] : injectedWallets,\n\t\t\t\t),\n\t\t\t)\n\t\t\t.subscribe(subscriber);\n\n\t\treturn () => {\n\t\t\tsubscription.unsubscribe();\n\t\t};\n\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n};\n\n/**\n * Compare two wallet arrays by their relevant properties (not functions).\n */\nconst walletsEqual = (\n\ta: SolanaInjectedWallet[],\n\tb: SolanaInjectedWallet[],\n): boolean => {\n\tif (a.length !== b.length) return false;\n\treturn a.every(\n\t\t(w, i) =>\n\t\t\tw.id === b[i]?.id &&\n\t\t\tw.isConnected === b[i]?.isConnected &&\n\t\t\tw.name === b[i]?.name,\n\t);\n};\n","import type { KheopskitPlatform, PlatformContext } from \"../types\";\nimport { getSolanaAccounts$ } from \"./accounts\";\nimport {\n\tDEFAULT_SOLANA_CHAIN,\n\tisSolanaChainId,\n\ttype SolanaChainId,\n} from \"./chains\";\nimport type { SolanaAccount, SolanaWallet } from \"./types\";\nimport { getSolanaWallets$ } from \"./wallets\";\n\nexport type SolanaPluginOptions = {\n\t/**\n\t * Solana cluster that account signers target. Each account also exposes a\n\t * `getSigner(chain)` factory for targeting another cluster.\n\t *\n\t * @default \"solana:mainnet\"\n\t */\n\tchain?: SolanaChainId;\n};\n\n/**\n * Solana platform plugin. Pass to `getKheopskit$({ platforms: [solana()] })`.\n *\n * @example\n * ```ts\n * import { solana } from \"@kheopskit/core/solana\";\n * solana({ chain: \"solana:mainnet\" });\n * ```\n */\nexport const solana = (\n\toptions: SolanaPluginOptions = {},\n): KheopskitPlatform<\"solana\", SolanaWallet, SolanaAccount> => {\n\tconst chain = options.chain ?? DEFAULT_SOLANA_CHAIN;\n\n\tif (!isSolanaChainId(chain)) {\n\t\tconsole.warn(\n\t\t\t`[kheopskit] Unknown solana chain: ${JSON.stringify(chain)}. Valid values: \"solana:mainnet\", \"solana:devnet\", \"solana:testnet\", \"solana:localnet\".`,\n\t\t);\n\t}\n\n\treturn {\n\t\tplatform: \"solana\",\n\t\tgetWallets$: (ctx: PlatformContext) =>\n\t\t\tgetSolanaWallets$(ctx.config, ctx.store),\n\t\tgetAccounts$: (wallets$) => getSolanaAccounts$(wallets$, chain),\n\t};\n};\n"]}
|