@ape.swap/bonds-sdk 7.0.2 → 7.0.4

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 (39) hide show
  1. package/dist/adapters/solana/index.js +1 -1
  2. package/dist/adapters/solana/index.js.map +1 -1
  3. package/dist/adapters/solana/state/fetchUsersBondsSOL.d.ts +5 -1
  4. package/dist/adapters/solana/state/fetchUsersBondsSOL.js +152 -154
  5. package/dist/adapters/solana/state/fetchUsersBondsSOL.js.map +1 -1
  6. package/dist/adapters/solana/state/fetchUsersBondsSOLMulticall.d.ts +12 -0
  7. package/dist/adapters/solana/state/fetchUsersBondsSOLMulticall.js +162 -0
  8. package/dist/adapters/solana/state/fetchUsersBondsSOLMulticall.js.map +1 -0
  9. package/dist/adapters/solana/utils/calculatePendingRewards.d.ts +2 -0
  10. package/dist/adapters/solana/utils/calculatePendingRewards.js +53 -0
  11. package/dist/adapters/solana/utils/calculatePendingRewards.js.map +1 -0
  12. package/dist/adapters/solana/utils/fetchUserAssetsSOL.d.ts +3 -0
  13. package/dist/adapters/solana/utils/fetchUserAssetsSOL.js +49 -0
  14. package/dist/adapters/solana/utils/fetchUserAssetsSOL.js.map +1 -0
  15. package/dist/adapters/solana/utils/getSolanaAccount.d.ts +5 -0
  16. package/dist/adapters/solana/utils/getSolanaAccount.js +26 -23
  17. package/dist/adapters/solana/utils/getSolanaAccount.js.map +1 -1
  18. package/dist/adapters/solana/utils/solanaMulticall.js +4 -2
  19. package/dist/adapters/solana/utils/solanaMulticall.js.map +1 -1
  20. package/dist/adapters/types.d.ts +1 -1
  21. package/dist/config/constants/networks.d.ts +1 -1
  22. package/dist/config/constants/networks.js +9 -7
  23. package/dist/config/constants/networks.js.map +1 -1
  24. package/dist/state/bonds/useUserBonds.d.ts +10 -1
  25. package/dist/state/bonds/useUserBonds.js +13 -9
  26. package/dist/state/bonds/useUserBonds.js.map +1 -1
  27. package/dist/styles.css +1 -1
  28. package/dist/views/Bonds/components/BondRows/ModalHandler.js +1 -1
  29. package/dist/views/Bonds/components/BondRows/ModalHandler.js.map +1 -1
  30. package/dist/views/Bonds/components/BondsMenu/BondsMenu.js +1 -1
  31. package/dist/views/Bonds/components/BondsMenu/BondsMenu.js.map +1 -1
  32. package/dist/views/FullBondsView/FullBondsView.js +2 -1
  33. package/dist/views/FullBondsView/FullBondsView.js.map +1 -1
  34. package/dist/views/FullBondsView/YourBondsStatus.d.ts +3 -0
  35. package/dist/views/FullBondsView/YourBondsStatus.js +54 -0
  36. package/dist/views/FullBondsView/YourBondsStatus.js.map +1 -0
  37. package/dist/views/YourBonds/components/YourBondsMenu/YourBondsMenu.js +2 -1
  38. package/dist/views/YourBonds/components/YourBondsMenu/YourBondsMenu.js.map +1 -1
  39. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+ export declare function calculatePendingRewards(connection: Connection, bondPda: PublicKey, bondTermPda: PublicKey, bondIssuancePda: PublicKey, nftMint: PublicKey): Promise<string>;
@@ -0,0 +1,53 @@
1
+ import { TransactionInstruction, Transaction, PublicKey } from '@solana/web3.js';
2
+ import { getU64Codec } from '@solana/kit';
3
+ import { Buffer } from 'buffer';
4
+ import { CLAIMABLE_PAYOUT_DISCRIMINATOR, PROGRAM_ID } from '../constants/solanaConstants.js';
5
+
6
+ async function calculatePendingRewards(connection, bondPda, bondTermPda, bondIssuancePda, nftMint) {
7
+ try {
8
+ const u64Codec = getU64Codec();
9
+ const currentTimestamp = Math.floor(Date.now() / 1000);
10
+ const encodedTimestamp = u64Codec.encode(BigInt(currentTimestamp));
11
+ // Instruction data
12
+ const instructionData = Buffer.concat([CLAIMABLE_PAYOUT_DISCRIMINATOR, Buffer.from(encodedTimestamp)]);
13
+ // Accounts
14
+ const keys = [
15
+ { pubkey: bondPda, isSigner: false, isWritable: true },
16
+ { pubkey: bondTermPda, isSigner: false, isWritable: false },
17
+ { pubkey: bondIssuancePda, isSigner: false, isWritable: false },
18
+ { pubkey: nftMint, isSigner: false, isWritable: false },
19
+ ];
20
+ // Instruction
21
+ const instruction = new TransactionInstruction({
22
+ keys,
23
+ programId: PROGRAM_ID,
24
+ data: instructionData,
25
+ });
26
+ // Transaction
27
+ const transaction = new Transaction();
28
+ const userPublicKey = new PublicKey('11111111111111111111111111111112'); // Dummy public key for fee payer
29
+ transaction.feePayer = userPublicKey;
30
+ transaction.add(instruction);
31
+ // Simulate
32
+ const simulation = await connection.simulateTransaction(transaction);
33
+ // Extract return value
34
+ const returnData = simulation.value.returnData;
35
+ if (returnData) {
36
+ const [data, encoding] = returnData.data;
37
+ if (encoding !== 'base64') {
38
+ throw new Error(`Unexpected return data encoding: ${encoding}`);
39
+ }
40
+ const decodedData = Buffer.from(data, 'base64');
41
+ return decodedData.readBigUInt64LE(0).toString();
42
+ }
43
+ // Fallback
44
+ return '0';
45
+ }
46
+ catch (error) {
47
+ console.error('Error calculating pending rewards:', error);
48
+ return '0';
49
+ }
50
+ }
51
+
52
+ export { calculatePendingRewards };
53
+ //# sourceMappingURL=calculatePendingRewards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calculatePendingRewards.js","sources":["../../../../src/adapters/solana/utils/calculatePendingRewards.ts"],"sourcesContent":["import { Connection, PublicKey, Transaction, TransactionInstruction } from '@solana/web3.js'\nimport { getU64Codec } from '@solana/kit'\nimport { Buffer } from 'buffer'\nimport { CLAIMABLE_PAYOUT_DISCRIMINATOR, PROGRAM_ID } from '../constants/solanaConstants'\n\nexport async function calculatePendingRewards(\n connection: Connection,\n bondPda: PublicKey,\n bondTermPda: PublicKey,\n bondIssuancePda: PublicKey,\n nftMint: PublicKey,\n): Promise<string> {\n try {\n const u64Codec = getU64Codec()\n\n const currentTimestamp = Math.floor(Date.now() / 1000)\n\n const encodedTimestamp = u64Codec.encode(BigInt(currentTimestamp))\n\n // Instruction data\n const instructionData = Buffer.concat([CLAIMABLE_PAYOUT_DISCRIMINATOR, Buffer.from(encodedTimestamp)])\n\n // Accounts\n const keys = [\n { pubkey: bondPda, isSigner: false, isWritable: true },\n { pubkey: bondTermPda, isSigner: false, isWritable: false },\n { pubkey: bondIssuancePda, isSigner: false, isWritable: false },\n { pubkey: nftMint, isSigner: false, isWritable: false },\n ]\n\n // Instruction\n const instruction = new TransactionInstruction({\n keys,\n programId: PROGRAM_ID,\n data: instructionData,\n })\n\n // Transaction\n const transaction = new Transaction()\n const userPublicKey = new PublicKey('11111111111111111111111111111112') // Dummy public key for fee payer\n transaction.feePayer = userPublicKey\n transaction.add(instruction)\n\n // Simulate\n const simulation = await connection.simulateTransaction(transaction)\n\n // Extract return value\n const returnData = simulation.value.returnData\n if (returnData) {\n const [data, encoding] = returnData.data\n if (encoding !== 'base64') {\n throw new Error(`Unexpected return data encoding: ${encoding}`)\n }\n\n const decodedData = Buffer.from(data, 'base64')\n return decodedData.readBigUInt64LE(0).toString()\n }\n\n // Fallback\n return '0'\n } catch (error) {\n console.error('Error calculating pending rewards:', error)\n return '0'\n }\n}\n"],"names":[],"mappings":";;;;;AAKO,eAAe,uBAAuB,CAC3C,UAAsB,EACtB,OAAkB,EAClB,WAAsB,EACtB,eAA0B,EAC1B,OAAkB,EAAA;AAElB,IAAA,IAAI;AACF,QAAA,MAAM,QAAQ,GAAG,WAAW,EAAE;AAE9B,QAAA,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAEtD,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;;AAGlE,QAAA,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,8BAA8B,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;;AAGtG,QAAA,MAAM,IAAI,GAAG;YACX,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE;YACtD,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;YAC3D,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;YAC/D,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;SACxD;;AAGD,QAAA,MAAM,WAAW,GAAG,IAAI,sBAAsB,CAAC;YAC7C,IAAI;AACJ,YAAA,SAAS,EAAE,UAAU;AACrB,YAAA,IAAI,EAAE,eAAe;AACtB,SAAA,CAAC;;AAGF,QAAA,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE;QACrC,MAAM,aAAa,GAAG,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAA;AACvE,QAAA,WAAW,CAAC,QAAQ,GAAG,aAAa;AACpC,QAAA,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC;;QAG5B,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,mBAAmB,CAAC,WAAW,CAAC;;AAGpE,QAAA,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU;QAC9C,IAAI,UAAU,EAAE;YACd,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,IAAI;AACxC,YAAA,IAAI,QAAQ,KAAK,QAAQ,EAAE;AACzB,gBAAA,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAA,CAAE,CAAC;YACjE;YAEA,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC;YAC/C,OAAO,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QAClD;;AAGA,QAAA,OAAO,GAAG;IACZ;IAAE,OAAO,KAAK,EAAE;AACd,QAAA,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC;AAC1D,QAAA,OAAO,GAAG;IACZ;AACF;;;;"}
@@ -0,0 +1,3 @@
1
+ import { HeliusAsset } from '../types/helius';
2
+ /** The user's bond NFTs (across the given collections) through Helius `searchAssets`, all pages. */
3
+ export declare function fetchUserAssetsSOL(user: string, collections: string[]): Promise<HeliusAsset[]>;
@@ -0,0 +1,49 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { getShuffledHeliusRPCs } from '../../../config/constants/networks.js';
3
+
4
+ const ASSETS_PER_PAGE = 1000;
5
+ // Safety net against a node that keeps returning full pages
6
+ const MAX_PAGES = 20;
7
+ /** One `searchAssets` page. A failed call (network, non-2xx, JSON-RPC error) is retried once on a different node. */
8
+ async function fetchAssetsPage(ownerAddress, collections, page) {
9
+ // Custom RPCs from the consumer are deliberately ignored: searchAssets is a Helius-only DAS method
10
+ const [primary, fallback] = getShuffledHeliusRPCs();
11
+ const body = JSON.stringify({
12
+ jsonrpc: '2.0',
13
+ id: '1',
14
+ method: 'searchAssets',
15
+ params: { ownerAddress, collections, page, limit: ASSETS_PER_PAGE },
16
+ });
17
+ const request = async (url) => {
18
+ const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body });
19
+ if (!response.ok)
20
+ throw new Error(`Helius searchAssets failed: HTTP ${response.status}`);
21
+ const data = await response.json();
22
+ if (data.error || !data.result?.items) {
23
+ throw new Error(`Helius searchAssets failed: ${data.error?.message ?? 'missing result'}`);
24
+ }
25
+ return data.result.items;
26
+ };
27
+ try {
28
+ return await request(primary);
29
+ }
30
+ catch (error) {
31
+ console.warn('Helius searchAssets failed, retrying with another node:', error);
32
+ return request(fallback ?? primary);
33
+ }
34
+ }
35
+ /** The user's bond NFTs (across the given collections) through Helius `searchAssets`, all pages. */
36
+ async function fetchUserAssetsSOL(user, collections) {
37
+ const ownerAddress = new PublicKey(user).toBase58();
38
+ const assets = [];
39
+ for (let page = 1; page <= MAX_PAGES; page++) {
40
+ const items = await fetchAssetsPage(ownerAddress, collections, page);
41
+ assets.push(...items);
42
+ if (items.length < ASSETS_PER_PAGE)
43
+ break;
44
+ }
45
+ return assets;
46
+ }
47
+
48
+ export { fetchUserAssetsSOL };
49
+ //# sourceMappingURL=fetchUserAssetsSOL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchUserAssetsSOL.js","sources":["../../../../src/adapters/solana/utils/fetchUserAssetsSOL.ts"],"sourcesContent":["import { PublicKey } from '@solana/web3.js'\nimport { getShuffledHeliusRPCs } from '../../../config/constants/networks'\nimport { HeliusApiResponse, HeliusAsset } from '../types/helius'\n\nconst ASSETS_PER_PAGE = 1000\n// Safety net against a node that keeps returning full pages\nconst MAX_PAGES = 20\n\n/** One `searchAssets` page. A failed call (network, non-2xx, JSON-RPC error) is retried once on a different node. */\nasync function fetchAssetsPage(ownerAddress: string, collections: string[], page: number): Promise<HeliusAsset[]> {\n // Custom RPCs from the consumer are deliberately ignored: searchAssets is a Helius-only DAS method\n const [primary, fallback] = getShuffledHeliusRPCs()\n const body = JSON.stringify({\n jsonrpc: '2.0',\n id: '1',\n method: 'searchAssets',\n params: { ownerAddress, collections, page, limit: ASSETS_PER_PAGE },\n })\n\n const request = async (url: string): Promise<HeliusAsset[]> => {\n const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body })\n if (!response.ok) throw new Error(`Helius searchAssets failed: HTTP ${response.status}`)\n const data: HeliusApiResponse & { error?: { message?: string } } = await response.json()\n if (data.error || !data.result?.items) {\n throw new Error(`Helius searchAssets failed: ${data.error?.message ?? 'missing result'}`)\n }\n return data.result.items\n }\n\n try {\n return await request(primary)\n } catch (error) {\n console.warn('Helius searchAssets failed, retrying with another node:', error)\n return request(fallback ?? primary)\n }\n}\n\n/** The user's bond NFTs (across the given collections) through Helius `searchAssets`, all pages. */\nexport async function fetchUserAssetsSOL(user: string, collections: string[]): Promise<HeliusAsset[]> {\n const ownerAddress = new PublicKey(user).toBase58()\n const assets: HeliusAsset[] = []\n for (let page = 1; page <= MAX_PAGES; page++) {\n const items = await fetchAssetsPage(ownerAddress, collections, page)\n assets.push(...items)\n if (items.length < ASSETS_PER_PAGE) break\n }\n return assets\n}\n"],"names":[],"mappings":";;;AAIA,MAAM,eAAe,GAAG,IAAI;AAC5B;AACA,MAAM,SAAS,GAAG,EAAE;AAEpB;AACA,eAAe,eAAe,CAAC,YAAoB,EAAE,WAAqB,EAAE,IAAY,EAAA;;IAEtF,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,qBAAqB,EAAE;AACnD,IAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;AAC1B,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,EAAE,EAAE,GAAG;AACP,QAAA,MAAM,EAAE,cAAc;QACtB,MAAM,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE;AACpE,KAAA,CAAC;AAEF,IAAA,MAAM,OAAO,GAAG,OAAO,GAAW,KAA4B;QAC5D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,CAAC;QAC5G,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,CAAA,iCAAA,EAAoC,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC;AACxF,QAAA,MAAM,IAAI,GAAyD,MAAM,QAAQ,CAAC,IAAI,EAAE;QACxF,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE;AACrC,YAAA,MAAM,IAAI,KAAK,CAAC,CAAA,4BAAA,EAA+B,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,gBAAgB,CAAA,CAAE,CAAC;QAC3F;AACA,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK;AAC1B,IAAA,CAAC;AAED,IAAA,IAAI;AACF,QAAA,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC;IAC/B;IAAE,OAAO,KAAK,EAAE;AACd,QAAA,OAAO,CAAC,IAAI,CAAC,yDAAyD,EAAE,KAAK,CAAC;AAC9E,QAAA,OAAO,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC;IACrC;AACF;AAEA;AACO,eAAe,kBAAkB,CAAC,IAAY,EAAE,WAAqB,EAAA;IAC1E,MAAM,YAAY,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;IACnD,MAAM,MAAM,GAAkB,EAAE;AAChC,IAAA,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,SAAS,EAAE,IAAI,EAAE,EAAE;QAC5C,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,YAAY,EAAE,WAAW,EAAE,IAAI,CAAC;AACpE,QAAA,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;AACrB,QAAA,IAAI,KAAK,CAAC,MAAM,GAAG,eAAe;YAAE;IACtC;AACA,IAAA,OAAO,MAAM;AACf;;;;"}
@@ -1,5 +1,10 @@
1
1
  import { BondIssuanceAccount, BondAccount, BondTermAccount, BondPricingAccount } from './codecs';
2
2
  export declare function getBondIssuanceAccountSolana(accountAddresses: string[]): Promise<BondIssuanceAccount[] | undefined>;
3
3
  export declare function getBondAccountSolana(accountAddresses: string[]): Promise<BondAccount[] | undefined>;
4
+ /**
5
+ * Batched version of getBondAccountSolana: the result is aligned with `accountAddresses` (a missing account yields
6
+ * `null` instead of aborting the whole batch) and requests are chunked to the RPC limit and sent in parallel.
7
+ */
8
+ export declare function getBondAccountsSolanaAligned(accountAddresses: string[]): Promise<(BondAccount | null)[]>;
4
9
  export declare function getBondTermAccountSolana(accountAddresses: string[]): Promise<BondTermAccount[] | undefined>;
5
10
  export declare function getBondPricingAccountSolana(accountAddresses: string[]): Promise<BondPricingAccount[] | undefined>;
@@ -31,30 +31,33 @@ async function getBondIssuanceAccountSolana(accountAddresses) {
31
31
  }
32
32
  return bondIssuanceAccounts;
33
33
  }
34
- async function getBondAccountSolana(accountAddresses) {
34
+ // getMultipleAccounts accepts up to 100 addresses per request
35
+ const MAX_ACCOUNTS_PER_REQUEST = 100;
36
+ /**
37
+ * Batched version of getBondAccountSolana: the result is aligned with `accountAddresses` (a missing account yields
38
+ * `null` instead of aborting the whole batch) and requests are chunked to the RPC limit and sent in parallel.
39
+ */
40
+ async function getBondAccountsSolanaAligned(accountAddresses) {
35
41
  const rpc = getSolanaRpc();
36
- const bondAddresses = accountAddresses.map((a) => address(a));
37
- const { value } = await rpc
38
- .getMultipleAccounts(bondAddresses, {
39
- encoding: 'base64',
40
- commitment: 'confirmed',
41
- })
42
- .send();
43
- if (!value?.length) {
44
- throw new Error(`Accounts not found for: ${bondAddresses}`);
45
- }
46
- const bondAccounts = [];
47
- for (const account of value) {
48
- if (!account?.data?.[0])
49
- return;
50
- const accountDataBytes = Buffer.from(account?.data?.[0], 'base64');
51
- if (!verifyBondDiscriminator(accountDataBytes)) {
52
- throw new Error(`Invalid account type. Expected Bond account at ${account.owner}`);
53
- }
54
- const bondAccount = bondDecoder.decode(accountDataBytes);
55
- bondAccounts.push(bondAccount);
42
+ const chunks = [];
43
+ for (let i = 0; i < accountAddresses.length; i += MAX_ACCOUNTS_PER_REQUEST) {
44
+ chunks.push(accountAddresses.slice(i, i + MAX_ACCOUNTS_PER_REQUEST));
56
45
  }
57
- return bondAccounts;
46
+ const decodedChunks = await Promise.all(chunks.map(async (chunk) => {
47
+ const { value } = await rpc
48
+ .getMultipleAccounts(chunk.map((a) => address(a)), { encoding: 'base64', commitment: 'confirmed' })
49
+ .send();
50
+ return value.map((account, i) => {
51
+ if (!account?.data?.[0])
52
+ return null;
53
+ const accountDataBytes = Buffer.from(account.data[0], 'base64');
54
+ if (!verifyBondDiscriminator(accountDataBytes)) {
55
+ throw new Error(`Invalid account type. Expected Bond account at ${chunk[i]}`);
56
+ }
57
+ return bondDecoder.decode(accountDataBytes);
58
+ });
59
+ }));
60
+ return decodedChunks.flat();
58
61
  }
59
62
  async function getBondTermAccountSolana(accountAddresses) {
60
63
  const rpc = getSolanaRpc();
@@ -107,5 +110,5 @@ async function getBondPricingAccountSolana(accountAddresses) {
107
110
  return bondPricingAccounts;
108
111
  }
109
112
 
110
- export { getBondAccountSolana, getBondIssuanceAccountSolana, getBondPricingAccountSolana, getBondTermAccountSolana };
113
+ export { getBondAccountsSolanaAligned, getBondIssuanceAccountSolana, getBondPricingAccountSolana, getBondTermAccountSolana };
111
114
  //# sourceMappingURL=getSolanaAccount.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getSolanaAccount.js","sources":["../../../../src/adapters/solana/utils/getSolanaAccount.ts"],"sourcesContent":["import { getSolanaRpc } from './solanaRpc'\nimport { address } from '@solana/kit'\nimport {\n bondIssuanceDecoder,\n verifyBondIssuanceDiscriminator,\n bondDecoder,\n verifyBondDiscriminator,\n bondTermDecoder,\n verifyBondTermDiscriminator,\n bondPricingDecoder,\n verifyBondPricingDiscriminator,\n BondIssuanceAccount,\n BondAccount,\n BondTermAccount,\n BondPricingAccount,\n} from './codecs'\nimport { Buffer } from 'buffer'\n\nexport async function getBondIssuanceAccountSolana(accountAddresses: string[]) {\n const rpc = getSolanaRpc()\n const bondIssuanceAddresses = accountAddresses.map((a) => address(a))\n\n const { value } = await rpc\n .getMultipleAccounts(bondIssuanceAddresses, {\n encoding: 'base64',\n commitment: 'confirmed',\n })\n .send()\n\n if (!value?.length) {\n throw new Error(`Accounts not found for: ${bondIssuanceAddresses}`)\n }\n\n const bondIssuanceAccounts: BondIssuanceAccount[] = []\n\n for (const account of value) {\n if (!account?.data?.[0]) return\n const accountDataBytes = Buffer.from(account?.data?.[0], 'base64')\n\n if (!verifyBondIssuanceDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected BondIssuance account at ${account.owner}`)\n }\n\n const bondIssuanceAccount = bondIssuanceDecoder.decode(accountDataBytes)\n bondIssuanceAccounts.push(bondIssuanceAccount)\n }\n\n return bondIssuanceAccounts\n}\n\nexport async function getBondAccountSolana(accountAddresses: string[]) {\n const rpc = getSolanaRpc()\n const bondAddresses = accountAddresses.map((a) => address(a))\n\n const { value } = await rpc\n .getMultipleAccounts(bondAddresses, {\n encoding: 'base64',\n commitment: 'confirmed',\n })\n .send()\n\n if (!value?.length) {\n throw new Error(`Accounts not found for: ${bondAddresses}`)\n }\n\n const bondAccounts: BondAccount[] = []\n\n for (const account of value) {\n if (!account?.data?.[0]) return\n const accountDataBytes = Buffer.from(account?.data?.[0], 'base64')\n\n if (!verifyBondDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected Bond account at ${account.owner}`)\n }\n\n const bondAccount = bondDecoder.decode(accountDataBytes)\n bondAccounts.push(bondAccount)\n }\n\n return bondAccounts\n}\n\nexport async function getBondTermAccountSolana(accountAddresses: string[]) {\n const rpc = getSolanaRpc()\n const bondTermAddresses = accountAddresses.map((a) => address(a))\n\n const { value } = await rpc\n .getMultipleAccounts(bondTermAddresses, {\n encoding: 'base64',\n commitment: 'confirmed',\n })\n .send()\n\n if (!value?.length) {\n throw new Error(`Accounts not found for: ${bondTermAddresses}`)\n }\n\n const bondTermAccounts: BondTermAccount[] = []\n\n for (const account of value) {\n if (!account?.data?.[0]) return\n const accountDataBytes = Buffer.from(account?.data?.[0], 'base64')\n\n if (!verifyBondTermDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected BondTerm account at ${account.owner}`)\n }\n\n const bondTermAccount = bondTermDecoder.decode(accountDataBytes)\n bondTermAccounts.push(bondTermAccount)\n }\n\n return bondTermAccounts\n}\n\nexport async function getBondPricingAccountSolana(accountAddresses: string[]) {\n const rpc = getSolanaRpc()\n const bondPricingAddresses = accountAddresses.map((a) => address(a))\n\n const { value } = await rpc\n .getMultipleAccounts(bondPricingAddresses, {\n encoding: 'base64',\n commitment: 'confirmed',\n })\n .send()\n\n if (!value?.length) {\n throw new Error(`Accounts not found for: ${bondPricingAddresses}`)\n }\n\n const bondPricingAccounts: BondPricingAccount[] = []\n\n for (const account of value) {\n if (!account?.data?.[0]) return\n const accountDataBytes = Buffer.from(account?.data?.[0], 'base64')\n\n if (!verifyBondPricingDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected BondPricing account at ${account.owner}`)\n }\n\n const bondPricingAccount = bondPricingDecoder.decode(accountDataBytes)\n bondPricingAccounts.push(bondPricingAccount)\n }\n\n return bondPricingAccounts\n}\n"],"names":[],"mappings":";;;;;;;;AAkBO,eAAe,4BAA4B,CAAC,gBAA0B,EAAA;AAC3E,IAAA,MAAM,GAAG,GAAG,YAAY,EAAE;AAC1B,IAAA,MAAM,qBAAqB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAErE,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM;SACrB,mBAAmB,CAAC,qBAAqB,EAAE;AAC1C,QAAA,QAAQ,EAAE,QAAQ;AAClB,QAAA,UAAU,EAAE,WAAW;KACxB;AACA,SAAA,IAAI,EAAE;AAET,IAAA,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE;AAClB,QAAA,MAAM,IAAI,KAAK,CAAC,2BAA2B,qBAAqB,CAAA,CAAE,CAAC;IACrE;IAEA,MAAM,oBAAoB,GAA0B,EAAE;AAEtD,IAAA,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE;AAC3B,QAAA,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC;YAAE;AACzB,QAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;AAElE,QAAA,IAAI,CAAC,+BAA+B,CAAC,gBAAgB,CAAC,EAAE;YACtD,MAAM,IAAI,KAAK,CAAC,CAAA,uDAAA,EAA0D,OAAO,CAAC,KAAK,CAAA,CAAE,CAAC;QAC5F;QAEA,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,MAAM,CAAC,gBAAgB,CAAC;AACxE,QAAA,oBAAoB,CAAC,IAAI,CAAC,mBAAmB,CAAC;IAChD;AAEA,IAAA,OAAO,oBAAoB;AAC7B;AAEO,eAAe,oBAAoB,CAAC,gBAA0B,EAAA;AACnE,IAAA,MAAM,GAAG,GAAG,YAAY,EAAE;AAC1B,IAAA,MAAM,aAAa,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAE7D,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM;SACrB,mBAAmB,CAAC,aAAa,EAAE;AAClC,QAAA,QAAQ,EAAE,QAAQ;AAClB,QAAA,UAAU,EAAE,WAAW;KACxB;AACA,SAAA,IAAI,EAAE;AAET,IAAA,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE;AAClB,QAAA,MAAM,IAAI,KAAK,CAAC,2BAA2B,aAAa,CAAA,CAAE,CAAC;IAC7D;IAEA,MAAM,YAAY,GAAkB,EAAE;AAEtC,IAAA,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE;AAC3B,QAAA,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC;YAAE;AACzB,QAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;AAElE,QAAA,IAAI,CAAC,uBAAuB,CAAC,gBAAgB,CAAC,EAAE;YAC9C,MAAM,IAAI,KAAK,CAAC,CAAA,+CAAA,EAAkD,OAAO,CAAC,KAAK,CAAA,CAAE,CAAC;QACpF;QAEA,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,gBAAgB,CAAC;AACxD,QAAA,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC;IAChC;AAEA,IAAA,OAAO,YAAY;AACrB;AAEO,eAAe,wBAAwB,CAAC,gBAA0B,EAAA;AACvE,IAAA,MAAM,GAAG,GAAG,YAAY,EAAE;AAC1B,IAAA,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAEjE,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM;SACrB,mBAAmB,CAAC,iBAAiB,EAAE;AACtC,QAAA,QAAQ,EAAE,QAAQ;AAClB,QAAA,UAAU,EAAE,WAAW;KACxB;AACA,SAAA,IAAI,EAAE;AAET,IAAA,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE;AAClB,QAAA,MAAM,IAAI,KAAK,CAAC,2BAA2B,iBAAiB,CAAA,CAAE,CAAC;IACjE;IAEA,MAAM,gBAAgB,GAAsB,EAAE;AAE9C,IAAA,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE;AAC3B,QAAA,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC;YAAE;AACzB,QAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;AAElE,QAAA,IAAI,CAAC,2BAA2B,CAAC,gBAAgB,CAAC,EAAE;YAClD,MAAM,IAAI,KAAK,CAAC,CAAA,mDAAA,EAAsD,OAAO,CAAC,KAAK,CAAA,CAAE,CAAC;QACxF;QAEA,MAAM,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,gBAAgB,CAAC;AAChE,QAAA,gBAAgB,CAAC,IAAI,CAAC,eAAe,CAAC;IACxC;AAEA,IAAA,OAAO,gBAAgB;AACzB;AAEO,eAAe,2BAA2B,CAAC,gBAA0B,EAAA;AAC1E,IAAA,MAAM,GAAG,GAAG,YAAY,EAAE;AAC1B,IAAA,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAEpE,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM;SACrB,mBAAmB,CAAC,oBAAoB,EAAE;AACzC,QAAA,QAAQ,EAAE,QAAQ;AAClB,QAAA,UAAU,EAAE,WAAW;KACxB;AACA,SAAA,IAAI,EAAE;AAET,IAAA,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE;AAClB,QAAA,MAAM,IAAI,KAAK,CAAC,2BAA2B,oBAAoB,CAAA,CAAE,CAAC;IACpE;IAEA,MAAM,mBAAmB,GAAyB,EAAE;AAEpD,IAAA,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE;AAC3B,QAAA,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC;YAAE;AACzB,QAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;AAElE,QAAA,IAAI,CAAC,8BAA8B,CAAC,gBAAgB,CAAC,EAAE;YACrD,MAAM,IAAI,KAAK,CAAC,CAAA,sDAAA,EAAyD,OAAO,CAAC,KAAK,CAAA,CAAE,CAAC;QAC3F;QAEA,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,MAAM,CAAC,gBAAgB,CAAC;AACtE,QAAA,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC;IAC9C;AAEA,IAAA,OAAO,mBAAmB;AAC5B;;;;"}
1
+ {"version":3,"file":"getSolanaAccount.js","sources":["../../../../src/adapters/solana/utils/getSolanaAccount.ts"],"sourcesContent":["import { getSolanaRpc } from './solanaRpc'\nimport { address } from '@solana/kit'\nimport {\n bondIssuanceDecoder,\n verifyBondIssuanceDiscriminator,\n bondDecoder,\n verifyBondDiscriminator,\n bondTermDecoder,\n verifyBondTermDiscriminator,\n bondPricingDecoder,\n verifyBondPricingDiscriminator,\n BondIssuanceAccount,\n BondAccount,\n BondTermAccount,\n BondPricingAccount,\n} from './codecs'\nimport { Buffer } from 'buffer'\n\nexport async function getBondIssuanceAccountSolana(accountAddresses: string[]) {\n const rpc = getSolanaRpc()\n const bondIssuanceAddresses = accountAddresses.map((a) => address(a))\n\n const { value } = await rpc\n .getMultipleAccounts(bondIssuanceAddresses, {\n encoding: 'base64',\n commitment: 'confirmed',\n })\n .send()\n\n if (!value?.length) {\n throw new Error(`Accounts not found for: ${bondIssuanceAddresses}`)\n }\n\n const bondIssuanceAccounts: BondIssuanceAccount[] = []\n\n for (const account of value) {\n if (!account?.data?.[0]) return\n const accountDataBytes = Buffer.from(account?.data?.[0], 'base64')\n\n if (!verifyBondIssuanceDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected BondIssuance account at ${account.owner}`)\n }\n\n const bondIssuanceAccount = bondIssuanceDecoder.decode(accountDataBytes)\n bondIssuanceAccounts.push(bondIssuanceAccount)\n }\n\n return bondIssuanceAccounts\n}\n\nexport async function getBondAccountSolana(accountAddresses: string[]) {\n const rpc = getSolanaRpc()\n const bondAddresses = accountAddresses.map((a) => address(a))\n\n const { value } = await rpc\n .getMultipleAccounts(bondAddresses, {\n encoding: 'base64',\n commitment: 'confirmed',\n })\n .send()\n\n if (!value?.length) {\n throw new Error(`Accounts not found for: ${bondAddresses}`)\n }\n\n const bondAccounts: BondAccount[] = []\n\n for (const account of value) {\n if (!account?.data?.[0]) return\n const accountDataBytes = Buffer.from(account?.data?.[0], 'base64')\n\n if (!verifyBondDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected Bond account at ${account.owner}`)\n }\n\n const bondAccount = bondDecoder.decode(accountDataBytes)\n bondAccounts.push(bondAccount)\n }\n\n return bondAccounts\n}\n\n// getMultipleAccounts accepts up to 100 addresses per request\nconst MAX_ACCOUNTS_PER_REQUEST = 100\n\n/**\n * Batched version of getBondAccountSolana: the result is aligned with `accountAddresses` (a missing account yields\n * `null` instead of aborting the whole batch) and requests are chunked to the RPC limit and sent in parallel.\n */\nexport async function getBondAccountsSolanaAligned(accountAddresses: string[]): Promise<(BondAccount | null)[]> {\n const rpc = getSolanaRpc()\n const chunks: string[][] = []\n for (let i = 0; i < accountAddresses.length; i += MAX_ACCOUNTS_PER_REQUEST) {\n chunks.push(accountAddresses.slice(i, i + MAX_ACCOUNTS_PER_REQUEST))\n }\n\n const decodedChunks = await Promise.all(\n chunks.map(async (chunk) => {\n const { value } = await rpc\n .getMultipleAccounts(\n chunk.map((a) => address(a)),\n { encoding: 'base64', commitment: 'confirmed' },\n )\n .send()\n\n return value.map((account, i) => {\n if (!account?.data?.[0]) return null\n const accountDataBytes = Buffer.from(account.data[0], 'base64')\n if (!verifyBondDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected Bond account at ${chunk[i]}`)\n }\n return bondDecoder.decode(accountDataBytes)\n })\n }),\n )\n\n return decodedChunks.flat()\n}\n\nexport async function getBondTermAccountSolana(accountAddresses: string[]) {\n const rpc = getSolanaRpc()\n const bondTermAddresses = accountAddresses.map((a) => address(a))\n\n const { value } = await rpc\n .getMultipleAccounts(bondTermAddresses, {\n encoding: 'base64',\n commitment: 'confirmed',\n })\n .send()\n\n if (!value?.length) {\n throw new Error(`Accounts not found for: ${bondTermAddresses}`)\n }\n\n const bondTermAccounts: BondTermAccount[] = []\n\n for (const account of value) {\n if (!account?.data?.[0]) return\n const accountDataBytes = Buffer.from(account?.data?.[0], 'base64')\n\n if (!verifyBondTermDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected BondTerm account at ${account.owner}`)\n }\n\n const bondTermAccount = bondTermDecoder.decode(accountDataBytes)\n bondTermAccounts.push(bondTermAccount)\n }\n\n return bondTermAccounts\n}\n\nexport async function getBondPricingAccountSolana(accountAddresses: string[]) {\n const rpc = getSolanaRpc()\n const bondPricingAddresses = accountAddresses.map((a) => address(a))\n\n const { value } = await rpc\n .getMultipleAccounts(bondPricingAddresses, {\n encoding: 'base64',\n commitment: 'confirmed',\n })\n .send()\n\n if (!value?.length) {\n throw new Error(`Accounts not found for: ${bondPricingAddresses}`)\n }\n\n const bondPricingAccounts: BondPricingAccount[] = []\n\n for (const account of value) {\n if (!account?.data?.[0]) return\n const accountDataBytes = Buffer.from(account?.data?.[0], 'base64')\n\n if (!verifyBondPricingDiscriminator(accountDataBytes)) {\n throw new Error(`Invalid account type. Expected BondPricing account at ${account.owner}`)\n }\n\n const bondPricingAccount = bondPricingDecoder.decode(accountDataBytes)\n bondPricingAccounts.push(bondPricingAccount)\n }\n\n return bondPricingAccounts\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { PublicKey } from '@solana/web3.js';
2
- import { getBondIssuanceAccountSolana, getBondPricingAccountSolana, getBondTermAccountSolana } from './getSolanaAccount.js';
2
+ import { getBondAccountsSolanaAligned, getBondIssuanceAccountSolana, getBondPricingAccountSolana, getBondTermAccountSolana } from './getSolanaAccount.js';
3
3
 
4
4
  /**
5
5
  * Reads multiple Anchor accounts in one batch from multiple programs
@@ -16,7 +16,9 @@ async function solanaMulticall(calls) {
16
16
  }, {});
17
17
  for (const [accountType, callIds] of Object.entries(callIdsGroupedByAccountType)) {
18
18
  if (accountType === 'bond') {
19
- results[accountType] = await getBondIssuanceAccountSolana(callIds.map((id) => id.toBase58()));
19
+ // Aligned with the calls (null for a missing account), so it skips the `[0] === null` reset below
20
+ results[accountType] = await getBondAccountsSolanaAligned(callIds.map((id) => id.toBase58()));
21
+ continue;
20
22
  }
21
23
  if (accountType === 'bondIssuance') {
22
24
  results[accountType] = await getBondIssuanceAccountSolana(callIds.map((id) => id.toBase58()));
@@ -1 +1 @@
1
- {"version":3,"file":"solanaMulticall.js","sources":["../../../../src/adapters/solana/utils/solanaMulticall.ts"],"sourcesContent":["import { PublicKey } from '@solana/web3.js'\nimport { getBondIssuanceAccountSolana, getBondPricingAccountSolana, getBondTermAccountSolana } from './getSolanaAccount'\n\nexport interface SolanaCall {\n accountAddress: string\n accountType: 'bond' | 'bondIssuance' | 'bondPricing' | 'bondTerm'\n}\n\n/**\n * Reads multiple Anchor accounts in one batch from multiple programs\n */\nexport async function solanaMulticall(calls: SolanaCall[]): Promise<Record<string, any>> {\n try {\n const results: Record<string, any> = {}\n\n const callIdsGroupedByAccountType = calls.reduce(\n (acc, call) => {\n if (!acc[call.accountType]) {\n acc[call.accountType] = []\n }\n acc[call.accountType].push(new PublicKey(call.accountAddress))\n return acc\n },\n {} as Record<string, PublicKey[]>,\n )\n\n for (const [accountType, callIds] of Object.entries(callIdsGroupedByAccountType)) {\n if (accountType === 'bond') {\n results[accountType] = await getBondIssuanceAccountSolana(callIds.map((id) => id.toBase58()))\n }\n if (accountType === 'bondIssuance') {\n results[accountType] = await getBondIssuanceAccountSolana(callIds.map((id) => id.toBase58()))\n }\n if (accountType === 'bondPricing') {\n results[accountType] = await getBondPricingAccountSolana(callIds.map((id) => id.toBase58()))\n }\n if (accountType === 'bondTerm') {\n results[accountType] = await getBondTermAccountSolana(callIds.map((id) => id.toBase58()))\n }\n if (results?.[accountType]?.[0] === null) {\n results[accountType] = []\n }\n }\n\n return results\n } catch (e) {\n console.error(e)\n return {}\n }\n}\n"],"names":[],"mappings":";;;AAQA;;AAEG;AACI,eAAe,eAAe,CAAC,KAAmB,EAAA;AACvD,IAAA,IAAI;QACF,MAAM,OAAO,GAAwB,EAAE;QAEvC,MAAM,2BAA2B,GAAG,KAAK,CAAC,MAAM,CAC9C,CAAC,GAAG,EAAE,IAAI,KAAI;YACZ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAC1B,gBAAA,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE;YAC5B;AACA,YAAA,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AAC9D,YAAA,OAAO,GAAG;QACZ,CAAC,EACD,EAAiC,CAClC;AAED,QAAA,KAAK,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,2BAA2B,CAAC,EAAE;AAChF,YAAA,IAAI,WAAW,KAAK,MAAM,EAAE;gBAC1B,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,4BAA4B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC/F;AACA,YAAA,IAAI,WAAW,KAAK,cAAc,EAAE;gBAClC,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,4BAA4B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC/F;AACA,YAAA,IAAI,WAAW,KAAK,aAAa,EAAE;gBACjC,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,2BAA2B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC9F;AACA,YAAA,IAAI,WAAW,KAAK,UAAU,EAAE;gBAC9B,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC3F;AACA,YAAA,IAAI,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE;AACxC,gBAAA,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE;YAC3B;QACF;AAEA,QAAA,OAAO,OAAO;IAChB;IAAE,OAAO,CAAC,EAAE;AACV,QAAA,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAChB,QAAA,OAAO,EAAE;IACX;AACF;;;;"}
1
+ {"version":3,"file":"solanaMulticall.js","sources":["../../../../src/adapters/solana/utils/solanaMulticall.ts"],"sourcesContent":["import { PublicKey } from '@solana/web3.js'\nimport {\n getBondAccountsSolanaAligned,\n getBondIssuanceAccountSolana,\n getBondPricingAccountSolana,\n getBondTermAccountSolana,\n} from './getSolanaAccount'\n\nexport interface SolanaCall {\n accountAddress: string\n accountType: 'bond' | 'bondIssuance' | 'bondPricing' | 'bondTerm'\n}\n\n/**\n * Reads multiple Anchor accounts in one batch from multiple programs\n */\nexport async function solanaMulticall(calls: SolanaCall[]): Promise<Record<string, any>> {\n try {\n const results: Record<string, any> = {}\n\n const callIdsGroupedByAccountType = calls.reduce(\n (acc, call) => {\n if (!acc[call.accountType]) {\n acc[call.accountType] = []\n }\n acc[call.accountType].push(new PublicKey(call.accountAddress))\n return acc\n },\n {} as Record<string, PublicKey[]>,\n )\n\n for (const [accountType, callIds] of Object.entries(callIdsGroupedByAccountType)) {\n if (accountType === 'bond') {\n // Aligned with the calls (null for a missing account), so it skips the `[0] === null` reset below\n results[accountType] = await getBondAccountsSolanaAligned(callIds.map((id) => id.toBase58()))\n continue\n }\n if (accountType === 'bondIssuance') {\n results[accountType] = await getBondIssuanceAccountSolana(callIds.map((id) => id.toBase58()))\n }\n if (accountType === 'bondPricing') {\n results[accountType] = await getBondPricingAccountSolana(callIds.map((id) => id.toBase58()))\n }\n if (accountType === 'bondTerm') {\n results[accountType] = await getBondTermAccountSolana(callIds.map((id) => id.toBase58()))\n }\n if (results?.[accountType]?.[0] === null) {\n results[accountType] = []\n }\n }\n\n return results\n } catch (e) {\n console.error(e)\n return {}\n }\n}\n"],"names":[],"mappings":";;;AAaA;;AAEG;AACI,eAAe,eAAe,CAAC,KAAmB,EAAA;AACvD,IAAA,IAAI;QACF,MAAM,OAAO,GAAwB,EAAE;QAEvC,MAAM,2BAA2B,GAAG,KAAK,CAAC,MAAM,CAC9C,CAAC,GAAG,EAAE,IAAI,KAAI;YACZ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AAC1B,gBAAA,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE;YAC5B;AACA,YAAA,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AAC9D,YAAA,OAAO,GAAG;QACZ,CAAC,EACD,EAAiC,CAClC;AAED,QAAA,KAAK,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,2BAA2B,CAAC,EAAE;AAChF,YAAA,IAAI,WAAW,KAAK,MAAM,EAAE;;gBAE1B,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,4BAA4B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC7F;YACF;AACA,YAAA,IAAI,WAAW,KAAK,cAAc,EAAE;gBAClC,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,4BAA4B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC/F;AACA,YAAA,IAAI,WAAW,KAAK,aAAa,EAAE;gBACjC,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,2BAA2B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC9F;AACA,YAAA,IAAI,WAAW,KAAK,UAAU,EAAE;gBAC9B,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC3F;AACA,YAAA,IAAI,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE;AACxC,gBAAA,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE;YAC3B;QACF;AAEA,QAAA,OAAO,OAAO;IAChB;IAAE,OAAO,CAAC,EAAE;AACV,QAAA,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAChB,QAAA,OAAO,EAAE;IACX;AACF;;;;"}
@@ -73,7 +73,7 @@ export interface ChainAdapter {
73
73
  usesRealtimeApi: boolean;
74
74
  /** For adapters that use the realtime API this is only the fallback path, used when that API fails. */
75
75
  fetchBondsData(chainId: ChainId, bonds: BillsConfig[], tokenPrices: TokenPrices[] | undefined, apiUrl: string): Promise<BondsData[]>;
76
- fetchUserBonds(chainId: ChainId, account: string, bonds: BillsConfig[], tokenPrices: Partial<Record<ChainId, TokenPrices[]>>): Promise<UserOwnedBillsData[]>;
76
+ fetchUserBonds(chainId: ChainId, account: string, bonds: BillsConfig[], tokenPrices: Partial<Record<ChainId, TokenPrices[]>>, apiUrl: string): Promise<UserOwnedBillsData[]>;
77
77
  /** false: skip the api-v2 /bills/multi-batch NFT metadata enrichment for this family's bills. */
78
78
  enrichUserBondsViaApi: boolean;
79
79
  getTokenBalance(chainId: ChainId, currency: 'NATIVE' | Token, account: string): Promise<string | null>;
@@ -1,5 +1,5 @@
1
1
  import { ChainId } from '@ape.swap/apeswap-lists';
2
2
  export declare const PUBLIC_RPC_URLS: Partial<Record<ChainId, string[]>>;
3
- export declare const HELIUS_SOL_RPC: string;
3
+ export declare const getShuffledHeliusRPCs: () => string[];
4
4
  export declare const setCustomRPCS: (urls: Partial<Record<ChainId, string[]>>) => void;
5
5
  export declare const getRPC: (chain: ChainId) => string;
@@ -84,13 +84,15 @@ const HELIUS_SOL_RPC_ENDPOINTS = [
84
84
  'https://mainnet.helius-rpc.com/?api-key=a5c4ea36-fa6b-4bcc-a7a4-e10012b9ea7e', // RandomApe personal mail
85
85
  ];
86
86
  // export const HELIUS_SOL_RPC_ENDPOINTS = ['https://devnet.helius-rpc.com/?api-key=095f6fc7-1be0-4d94-a737-4a5ee0d82ea5'] //devnet
87
- // Function to get a random Helius SOL RPC endpoint
88
- const getRandomHeliusRPC = () => {
89
- const randomIndex = Math.floor(Math.random() * HELIUS_SOL_RPC_ENDPOINTS.length);
90
- return HELIUS_SOL_RPC_ENDPOINTS[randomIndex];
87
+ // Helius endpoints in random order, so load spreads across the keys and a retry can use a different one
88
+ const getShuffledHeliusRPCs = () => {
89
+ const endpoints = [...HELIUS_SOL_RPC_ENDPOINTS];
90
+ for (let i = endpoints.length - 1; i > 0; i--) {
91
+ const j = Math.floor(Math.random() * (i + 1));
92
+ [endpoints[i], endpoints[j]] = [endpoints[j], endpoints[i]];
93
+ }
94
+ return endpoints;
91
95
  };
92
- // Keep the current export for backward compatibility
93
- const HELIUS_SOL_RPC = getRandomHeliusRPC();
94
96
  // Custom RPC registry — set by the consumer via the `customRPCS` prop
95
97
  let _customRPCS = {};
96
98
  const setCustomRPCS = (urls) => {
@@ -100,5 +102,5 @@ const getRPC = (chain) => {
100
102
  return _customRPCS?.[chain]?.[0] ?? PUBLIC_RPC_URLS?.[chain]?.[0];
101
103
  };
102
104
 
103
- export { HELIUS_SOL_RPC, PUBLIC_RPC_URLS, getRPC, setCustomRPCS };
105
+ export { PUBLIC_RPC_URLS, getRPC, getShuffledHeliusRPCs, setCustomRPCS };
104
106
  //# sourceMappingURL=networks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"networks.js","sources":["../../../src/config/constants/networks.ts"],"sourcesContent":["import { ChainId } from '@ape.swap/apeswap-lists'\nimport { APTOS_FULLNODE_URL } from '../../constants/aptosConstants'\n\nexport const PUBLIC_RPC_URLS: Partial<Record<ChainId, string[]>> = {\n [ChainId.BSC]: [\n 'https://bsc-dataseed.binance.org/',\n 'https://bsc-dataseed1.defibit.io',\n 'https://endpoints.omniatech.io/v1/bsc/mainnet/public',\n ],\n [ChainId.ARBITRUM]: ['https://arb1.arbitrum.io/rpc'],\n [ChainId.BSC_TESTNET]: ['https://data-seed-prebsc-2-s3.binance.org:8545/'],\n [ChainId.MATIC]: [\n 'https://polygon.drpc.org',\n 'https://1rpc.io/matic',\n 'https://polygon-rpc.com/', // this is now freemium\n 'https://polygon-mainnet.public.blastapi.io/',\n 'https://rpc-mainnet.matic.network',\n 'https://matic-mainnet.chainstacklabs.com',\n ],\n [ChainId.MAINNET]: [\n 'https://ethereum-rpc.publicnode.com',\n 'https://eth.drpc.org',\n 'https://eth-mainnet.public.blastapi.io',\n 'https://rpc.ankr.com/eth',\n ],\n [ChainId.TLOS]: ['https://mainnet.telos.net/evm'],\n [ChainId.INEVM]: ['https://mainnet.rpc.inevm.com/http'],\n [ChainId.SEPOLIA]: ['https://eth-sepolia-public.unifra.io'],\n [ChainId.LINEA]: [\n 'https://rpc.linea.build',\n 'https://linea.drpc.org',\n 'https://linea.blockpi.network/v1/rpc/public',\n 'https://linea.decubate.com',\n ],\n [ChainId.LIGHTLINK]: [\n 'https://replicator.phoenix.lightlink.io/rpc/v1',\n 'https://endpoints.omniatech.io/v1/lightlink/phoenix/public',\n ],\n [ChainId.IOTA]: ['https://json-rpc.evm.iotaledger.net/'],\n [ChainId.IOTA_TESTNET]: ['https://json-rpc.evm.testnet.iotaledger.net/'],\n [ChainId.BASE]: ['https://base-rpc.publicnode.com', 'https://mainnet.base.org'],\n [ChainId.GRAPHLINQ]: ['https://glq-dataseed.graphlinq.io'],\n [ChainId.AVAX]: ['https://avalanche-c-chain-rpc.publicnode.com', 'https://avax.meowrpc.com'],\n [ChainId.BLAST]: ['https://rpc.blast.io'],\n [ChainId.CROSSFI]: ['https://rpc.mainnet.ms'],\n [ChainId.MONAD_TESTNET]: ['https://testnet-rpc2.monad.xyz/52227f026fa8fac9e2014c58fbf5643369b3bfc6'],\n [ChainId.MONAD]: [\n 'https://rpc.monad.xyz',\n 'https://rpc1.monad.xyz',\n 'https://rpc2.monad.xyz',\n 'https://rpc3.monad.xyz',\n 'https://rpc4.monad.xyz',\n ],\n [ChainId.SONIC]: ['https://rpc.soniclabs.com'],\n [ChainId.BERACHAIN]: ['https://rpc.berachain.com', 'https://berachain.drpc.org'],\n [ChainId.KATANA]: ['https://rpc-katana.t.conduit.xyz/NRcSLqEG4Hw55GzTSu6Sratq94kKtUGfH'],\n [ChainId.UNICHAIN]: ['https://unichain-rpc.publicnode.com', 'https://unichain.drpc.org'],\n [ChainId.MEGAETH_TESTNET]: ['https://carrot.megaeth.com/rpc'],\n [ChainId.HYPEREVM]: ['https://rpc.hyperliquid.xyz/evm'],\n [ChainId.BITTENSOR_TESTNET]: ['https://bittensor-testnet-lite-public.nodies.app'],\n [ChainId.ROBINHOOD]: ['https://rpc.mainnet.chain.robinhood.com'],\n [ChainId.L1X]: ['https://v2-mainnet-rpc.l1x.foundation'],\n\n // Aptos fullnode — URL is clean; the API key goes in the Authorization\n // header, not as a query param (see aptosConstants.ts). The cast on\n // APTOS_CHAIN_ID is required because the synthetic id is not in the\n // ChainId enum yet.\n [ChainId.APTOS]: [APTOS_FULLNODE_URL],\n\n // Sui fullnode — public RPC, no API key required (see suiConstants.ts).\n [ChainId.SUI]: ['https://fullnode.mainnet.sui.io:443'],\n\n // SOL RPC is not public. Production URL (morning-autumn-dream) is domain-protected, development URL (ancient-cold-sailboat) is free, use with caution.\n [ChainId.SOL]:\n process.env.NODE_ENV === 'production'\n ? ['https://morning-autumn-dream.solana-mainnet.quiknode.pro/1ef6069950c798a43a112c0fe5eb157309427db8']\n : [\n 'https://ancient-cold-sailboat.solana-mainnet.quiknode.pro/da13400ad8d0035313f3e71c6a37c107d0d0334b',\n 'https://mainnet.helius-rpc.com/?api-key=d80b11e0-692f-4da0-91d6-830799c8c385',\n ], // mainnet\n // [ChainId.SOL]: ['https://devnet.helius-rpc.com/?api-key=095f6fc7-1be0-4d94-a737-4a5ee0d82ea5'], // devnet\n}\n\n// Multiple Helius SOL RPC endpoints for rotation\nconst HELIUS_SOL_RPC_ENDPOINTS = [\n 'https://mainnet.helius-rpc.com/?api-key=d80b11e0-692f-4da0-91d6-830799c8c385', // apefede09@gmail.com\n 'https://mainnet.helius-rpc.com/?api-key=8631ce42-9000-490d-9ac3-f3a81de508b2', // apebond.design@gmail.com\n 'https://mainnet.helius-rpc.com/?api-key=c097651d-ae13-4ab4-ae4c-fef7e48d4561', // n0mbr3al3at0r10@gmail.com\n 'https://mainnet.helius-rpc.com/?api-key=a5c4ea36-fa6b-4bcc-a7a4-e10012b9ea7e', // RandomApe personal mail\n]\n\n// export const HELIUS_SOL_RPC_ENDPOINTS = ['https://devnet.helius-rpc.com/?api-key=095f6fc7-1be0-4d94-a737-4a5ee0d82ea5'] //devnet\n\n// Function to get a random Helius SOL RPC endpoint\nconst getRandomHeliusRPC = (): string => {\n const randomIndex = Math.floor(Math.random() * HELIUS_SOL_RPC_ENDPOINTS.length)\n return HELIUS_SOL_RPC_ENDPOINTS[randomIndex]\n}\n\n// Keep the current export for backward compatibility\nexport const HELIUS_SOL_RPC = getRandomHeliusRPC()\n\n// Custom RPC registry — set by the consumer via the `customRPCS` prop\nlet _customRPCS: Partial<Record<ChainId, string[]>> = {}\n\nexport const setCustomRPCS = (urls: Partial<Record<ChainId, string[]>>) => {\n _customRPCS = urls\n}\n\nexport const getRPC = (chain: ChainId): string => {\n return _customRPCS?.[chain]?.[0] ?? (PUBLIC_RPC_URLS?.[chain]?.[0] as string)\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"networks.js","sources":["../../../src/config/constants/networks.ts"],"sourcesContent":["import { ChainId } from '@ape.swap/apeswap-lists'\nimport { APTOS_FULLNODE_URL } from '../../constants/aptosConstants'\n\nexport const PUBLIC_RPC_URLS: Partial<Record<ChainId, string[]>> = {\n [ChainId.BSC]: [\n 'https://bsc-dataseed.binance.org/',\n 'https://bsc-dataseed1.defibit.io',\n 'https://endpoints.omniatech.io/v1/bsc/mainnet/public',\n ],\n [ChainId.ARBITRUM]: ['https://arb1.arbitrum.io/rpc'],\n [ChainId.BSC_TESTNET]: ['https://data-seed-prebsc-2-s3.binance.org:8545/'],\n [ChainId.MATIC]: [\n 'https://polygon.drpc.org',\n 'https://1rpc.io/matic',\n 'https://polygon-rpc.com/', // this is now freemium\n 'https://polygon-mainnet.public.blastapi.io/',\n 'https://rpc-mainnet.matic.network',\n 'https://matic-mainnet.chainstacklabs.com',\n ],\n [ChainId.MAINNET]: [\n 'https://ethereum-rpc.publicnode.com',\n 'https://eth.drpc.org',\n 'https://eth-mainnet.public.blastapi.io',\n 'https://rpc.ankr.com/eth',\n ],\n [ChainId.TLOS]: ['https://mainnet.telos.net/evm'],\n [ChainId.INEVM]: ['https://mainnet.rpc.inevm.com/http'],\n [ChainId.SEPOLIA]: ['https://eth-sepolia-public.unifra.io'],\n [ChainId.LINEA]: [\n 'https://rpc.linea.build',\n 'https://linea.drpc.org',\n 'https://linea.blockpi.network/v1/rpc/public',\n 'https://linea.decubate.com',\n ],\n [ChainId.LIGHTLINK]: [\n 'https://replicator.phoenix.lightlink.io/rpc/v1',\n 'https://endpoints.omniatech.io/v1/lightlink/phoenix/public',\n ],\n [ChainId.IOTA]: ['https://json-rpc.evm.iotaledger.net/'],\n [ChainId.IOTA_TESTNET]: ['https://json-rpc.evm.testnet.iotaledger.net/'],\n [ChainId.BASE]: ['https://base-rpc.publicnode.com', 'https://mainnet.base.org'],\n [ChainId.GRAPHLINQ]: ['https://glq-dataseed.graphlinq.io'],\n [ChainId.AVAX]: ['https://avalanche-c-chain-rpc.publicnode.com', 'https://avax.meowrpc.com'],\n [ChainId.BLAST]: ['https://rpc.blast.io'],\n [ChainId.CROSSFI]: ['https://rpc.mainnet.ms'],\n [ChainId.MONAD_TESTNET]: ['https://testnet-rpc2.monad.xyz/52227f026fa8fac9e2014c58fbf5643369b3bfc6'],\n [ChainId.MONAD]: [\n 'https://rpc.monad.xyz',\n 'https://rpc1.monad.xyz',\n 'https://rpc2.monad.xyz',\n 'https://rpc3.monad.xyz',\n 'https://rpc4.monad.xyz',\n ],\n [ChainId.SONIC]: ['https://rpc.soniclabs.com'],\n [ChainId.BERACHAIN]: ['https://rpc.berachain.com', 'https://berachain.drpc.org'],\n [ChainId.KATANA]: ['https://rpc-katana.t.conduit.xyz/NRcSLqEG4Hw55GzTSu6Sratq94kKtUGfH'],\n [ChainId.UNICHAIN]: ['https://unichain-rpc.publicnode.com', 'https://unichain.drpc.org'],\n [ChainId.MEGAETH_TESTNET]: ['https://carrot.megaeth.com/rpc'],\n [ChainId.HYPEREVM]: ['https://rpc.hyperliquid.xyz/evm'],\n [ChainId.BITTENSOR_TESTNET]: ['https://bittensor-testnet-lite-public.nodies.app'],\n [ChainId.ROBINHOOD]: ['https://rpc.mainnet.chain.robinhood.com'],\n [ChainId.L1X]: ['https://v2-mainnet-rpc.l1x.foundation'],\n\n // Aptos fullnode — URL is clean; the API key goes in the Authorization\n // header, not as a query param (see aptosConstants.ts). The cast on\n // APTOS_CHAIN_ID is required because the synthetic id is not in the\n // ChainId enum yet.\n [ChainId.APTOS]: [APTOS_FULLNODE_URL],\n\n // Sui fullnode — public RPC, no API key required (see suiConstants.ts).\n [ChainId.SUI]: ['https://fullnode.mainnet.sui.io:443'],\n\n // SOL RPC is not public. Production URL (morning-autumn-dream) is domain-protected, development URL (ancient-cold-sailboat) is free, use with caution.\n [ChainId.SOL]:\n process.env.NODE_ENV === 'production'\n ? ['https://morning-autumn-dream.solana-mainnet.quiknode.pro/1ef6069950c798a43a112c0fe5eb157309427db8']\n : [\n 'https://ancient-cold-sailboat.solana-mainnet.quiknode.pro/da13400ad8d0035313f3e71c6a37c107d0d0334b',\n 'https://mainnet.helius-rpc.com/?api-key=d80b11e0-692f-4da0-91d6-830799c8c385',\n ], // mainnet\n // [ChainId.SOL]: ['https://devnet.helius-rpc.com/?api-key=095f6fc7-1be0-4d94-a737-4a5ee0d82ea5'], // devnet\n}\n\n// Multiple Helius SOL RPC endpoints for rotation\nconst HELIUS_SOL_RPC_ENDPOINTS = [\n 'https://mainnet.helius-rpc.com/?api-key=d80b11e0-692f-4da0-91d6-830799c8c385', // apefede09@gmail.com\n 'https://mainnet.helius-rpc.com/?api-key=8631ce42-9000-490d-9ac3-f3a81de508b2', // apebond.design@gmail.com\n 'https://mainnet.helius-rpc.com/?api-key=c097651d-ae13-4ab4-ae4c-fef7e48d4561', // n0mbr3al3at0r10@gmail.com\n 'https://mainnet.helius-rpc.com/?api-key=a5c4ea36-fa6b-4bcc-a7a4-e10012b9ea7e', // RandomApe personal mail\n]\n\n// export const HELIUS_SOL_RPC_ENDPOINTS = ['https://devnet.helius-rpc.com/?api-key=095f6fc7-1be0-4d94-a737-4a5ee0d82ea5'] //devnet\n\n// Helius endpoints in random order, so load spreads across the keys and a retry can use a different one\nexport const getShuffledHeliusRPCs = (): string[] => {\n const endpoints = [...HELIUS_SOL_RPC_ENDPOINTS]\n for (let i = endpoints.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[endpoints[i], endpoints[j]] = [endpoints[j], endpoints[i]]\n }\n return endpoints\n}\n\n// Custom RPC registry — set by the consumer via the `customRPCS` prop\nlet _customRPCS: Partial<Record<ChainId, string[]>> = {}\n\nexport const setCustomRPCS = (urls: Partial<Record<ChainId, string[]>>) => {\n _customRPCS = urls\n}\n\nexport const getRPC = (chain: ChainId): string => {\n return _customRPCS?.[chain]?.[0] ?? (PUBLIC_RPC_URLS?.[chain]?.[0] as string)\n}\n"],"names":[],"mappings":"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"}
@@ -2,6 +2,15 @@ import { QueryClient, UseQueryResult } from '@tanstack/react-query';
2
2
  import { BillsConfig, ChainId } from '@ape.swap/apeswap-lists';
3
3
  import { UserBill } from '../../types/yourbonds';
4
4
  import type { Ecosystem } from '../../adapters/types';
5
- export default function useUserBonds(): UseQueryResult<UserBill[]>;
5
+ /** What the query caches: the bills plus the chains whose bills couldn't be fetched. */
6
+ export interface UserBondsResult {
7
+ bills: UserBill[];
8
+ /** Chains (with a registered adapter and a connected account) whose fetch failed. Their bills are missing from `bills`. */
9
+ failedChains: ChainId[];
10
+ }
11
+ export default function useUserBonds(): Omit<UseQueryResult<UserBondsResult>, 'data'> & {
12
+ data: UserBill[] | undefined;
13
+ failedChains: ChainId[];
14
+ };
6
15
  /** @param accounts the connected account of each family, by ecosystem (see useChainAccount) */
7
16
  export declare const getUserBonds: (accounts: Partial<Record<Ecosystem, string | null>>, bondList: Record<ChainId, BillsConfig[]>, queryClient: QueryClient) => Promise<UserBill[]>;
@@ -16,7 +16,7 @@ function useUserBonds() {
16
16
  const { address: addressAptos } = useChainAccount('aptos');
17
17
  const { address: addressSUI } = useChainAccount('sui');
18
18
  const { data: tokenPrices } = useTokenPrices();
19
- return useQuery({
19
+ const query = useQuery({
20
20
  queryKey: [
21
21
  QUERY_KEYS.USER_BONDS,
22
22
  addressEVM,
@@ -25,7 +25,7 @@ function useUserBonds() {
25
25
  addressSUI,
26
26
  Object.keys(tokenPrices ?? {})?.length ?? null,
27
27
  ],
28
- queryFn: ({ client }) => getUserBonds({ evm: addressEVM, sol: addressSOL, aptos: addressAptos, sui: addressSUI }, bondList, client),
28
+ queryFn: ({ client }) => fetchUserBonds({ evm: addressEVM, sol: addressSOL, aptos: addressAptos, sui: addressSUI }, bondList, client),
29
29
  enabled: !!bondList && !!(addressEVM || addressSOL || addressAptos || addressSUI) && !!tokenPrices,
30
30
  refetchInterval: 120000,
31
31
  refetchOnWindowFocus: false,
@@ -33,21 +33,25 @@ function useUserBonds() {
33
33
  refetchOnReconnect: false,
34
34
  retry: 1,
35
35
  });
36
+ // `data` stays the plain bills array for consumers; failed chains are exposed next to it
37
+ return { ...query, data: query.data?.bills, failedChains: query.data?.failedChains ?? [] };
36
38
  }
37
39
  /** @param accounts the connected account of each family, by ecosystem (see useChainAccount) */
38
- const getUserBonds = async (accounts, bondList, queryClient) => {
40
+ const getUserBonds = async (accounts, bondList, queryClient) => (await fetchUserBonds(accounts, bondList, queryClient)).bills;
41
+ const fetchUserBonds = async (accounts, bondList, queryClient) => {
39
42
  const { chains, urls } = queryClient?.getQueryData([QUERY_KEYS.SDK_CONFIG]);
40
43
  const apiUrl = urls['apiV2'];
41
44
  const tokenPrices = queryClient?.getQueryData([QUERY_KEYS.TOKEN_PRICES]);
42
45
  try {
43
- const results = await Promise.allSettled(chains
44
- .filter((chain) => bondList[chain])
45
- .map((chain) => {
46
+ const chainsToFetch = chains.filter((chain) => bondList[chain]);
47
+ const results = await Promise.allSettled(chainsToFetch.map((chain) => {
46
48
  // Chains without a registered adapter are unsupported
47
49
  const adapter = getAdapterForChain(chain);
48
50
  const account = adapter && accounts[adapter.ecosystem];
49
- return adapter && account ? adapter.fetchUserBonds(chain, account, bondList[chain], tokenPrices) : [];
51
+ return adapter && account ? adapter.fetchUserBonds(chain, account, bondList[chain], tokenPrices, apiUrl) : [];
50
52
  }));
53
+ // `results` follows `chainsToFetch`. Chains skipped above (no adapter / no account) resolve to [], not a failure.
54
+ const failedChains = chainsToFetch.filter((_chain, i) => results[i].status === 'rejected');
51
55
  // Filter out only fulfilled promises
52
56
  const fulfilledResults = results
53
57
  .filter((result) => result.status === 'fulfilled')
@@ -78,7 +82,7 @@ const getUserBonds = async (accounts, bondList, queryClient) => {
78
82
  }
79
83
  catch (e) {
80
84
  console.error(e);
81
- return onChainData;
85
+ return { bills: onChainData, failedChains };
82
86
  }
83
87
  // Enrich on-chain data with API data.
84
88
  // Bills that weren't sent to api-v2 keep the nftData their fetcher populated instead of being overwritten with
@@ -99,7 +103,7 @@ const getUserBonds = async (accounts, bondList, queryClient) => {
99
103
  nftData,
100
104
  };
101
105
  });
102
- return enrichedData;
106
+ return { bills: enrichedData, failedChains };
103
107
  }
104
108
  catch (e) {
105
109
  console.error(e);
@@ -1 +1 @@
1
- {"version":3,"file":"useUserBonds.js","sources":["../../../src/state/bonds/useUserBonds.ts"],"sourcesContent":["import { QueryClient, useQuery, UseQueryResult } from '@tanstack/react-query'\nimport { QUERY_KEYS } from '../../config/constants/queryKeys'\nimport { BillsConfig, ChainId } from '@ape.swap/apeswap-lists'\nimport useBondsList from './useBondsList'\nimport { UserBill, UserBillNftData } from '../../types/yourbonds'\nimport { SDKProps } from '../useSDKConfig'\nimport useTokenPrices, { TokenPrices } from '../tokenPrices/useTokenPrices'\nimport { reportError } from '../../utils/reportError'\nimport useChainAccount from '../chainAccount/useChainAccount'\nimport { apiPost } from '../../utils/httpClient'\nimport { getAdapterForChain } from '../../adapters/registry'\nimport type { Ecosystem } from '../../adapters/types'\n\nexport default function useUserBonds(): UseQueryResult<UserBill[]> {\n // First fetch the full list of bonds\n const { data: bondList } = useBondsList()\n const { address: addressEVM } = useChainAccount('evm')\n const { address: addressSOL } = useChainAccount('sol')\n const { address: addressAptos } = useChainAccount('aptos')\n const { address: addressSUI } = useChainAccount('sui')\n const { data: tokenPrices } = useTokenPrices()\n return useQuery({\n queryKey: [\n QUERY_KEYS.USER_BONDS,\n addressEVM,\n addressSOL,\n addressAptos,\n addressSUI,\n Object.keys(tokenPrices ?? {})?.length ?? null,\n ],\n queryFn: ({ client }) =>\n getUserBonds({ evm: addressEVM, sol: addressSOL, aptos: addressAptos, sui: addressSUI }, bondList!, client),\n enabled: !!bondList && !!(addressEVM || addressSOL || addressAptos || addressSUI) && !!tokenPrices,\n refetchInterval: 120000,\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n refetchOnReconnect: false,\n retry: 1,\n })\n}\n\n/** @param accounts the connected account of each family, by ecosystem (see useChainAccount) */\nexport const getUserBonds = async (\n accounts: Partial<Record<Ecosystem, string | null>>,\n bondList: Record<ChainId, BillsConfig[]>,\n queryClient: QueryClient,\n): Promise<UserBill[]> => {\n const { chains, urls } = queryClient?.getQueryData([QUERY_KEYS.SDK_CONFIG]) as SDKProps\n const apiUrl = urls['apiV2']\n const tokenPrices: Partial<Record<ChainId, TokenPrices[]>> = queryClient?.getQueryData([QUERY_KEYS.TOKEN_PRICES])!\n\n try {\n const results = await Promise.allSettled(\n chains\n .filter((chain: ChainId) => bondList[chain])\n .map((chain: ChainId) => {\n // Chains without a registered adapter are unsupported\n const adapter = getAdapterForChain(chain)\n const account = adapter && accounts[adapter.ecosystem]\n return adapter && account ? adapter.fetchUserBonds(chain, account, bondList[chain], tokenPrices) : []\n }),\n )\n\n // Filter out only fulfilled promises\n const fulfilledResults = results\n .filter((result): result is PromiseFulfilledResult<any> => result.status === 'fulfilled')\n .map((result) => result.value)\n\n const onChainData: UserBill[] = fulfilledResults.flat().flatMap((result) => result.userOwnedBills)\n\n // Prepare body for batch API call\n // api-v2 doesn't support adapters with enrichUserBondsViaApi: false (e.g. Aptos, Sui). Their bills are read\n // on-chain, with no /bills/multi-batch enrichment, and use the placeholder image from their constants.\n const enrichViaApi = (chainId?: ChainId) => getAdapterForChain(chainId as ChainId)?.enrichUserBondsViaApi ?? true\n const body = Object.values(\n onChainData\n .filter((data) => enrichViaApi(data?.bond?.chainId))\n .reduce(\n (acc, data) => {\n const contract =\n data?.bond?.chainId === ChainId.SOL ? data.bond.contractAddress[data.bond.chainId] : data.billNftAddress\n const key = `${data?.bond?.chainId}-${contract}`\n\n if (!acc[key]) {\n acc[key] = {\n chainId: data?.bond?.chainId as number,\n contract: contract as string,\n billIds: [],\n }\n }\n\n acc[key].billIds.push(parseInt(data.id))\n return acc\n },\n {} as Record<string, { chainId: number; contract: string; billIds: number[] }>,\n ),\n )\n let responseData\n\n try {\n responseData = await apiPost<any[]>(`${apiUrl}/bills/multi-batch`, body, { timeoutMs: 40000 })\n } catch (e) {\n console.error(e)\n return onChainData\n }\n // Enrich on-chain data with API data.\n // Bills that weren't sent to api-v2 keep the nftData their fetcher populated instead of being overwritten with\n // undefined.\n const enrichedData: UserBill[] = onChainData.map((userBond) => {\n if (!enrichViaApi(userBond.bond?.chainId)) return userBond\n\n const nftDataResponse = responseData?.find((nft: any) => {\n const contract = nft.contract.toLowerCase()\n const chain = nft.chainId\n\n // API uses contractAddress for Solana bonds instead of NFT Address\n const contractToCompare =\n chain === ChainId.SOL ? userBond.bond?.contractAddress[ChainId.SOL] : userBond.billNftAddress\n return contractToCompare?.toLowerCase() === contract && userBond.bond?.chainId === chain\n })\n const nftData: UserBillNftData | undefined = nftDataResponse?.bills?.find(\n (billApiData: UserBillNftData) => billApiData.tokenId === parseInt(userBond.id),\n )\n return {\n ...userBond,\n nftData,\n }\n })\n\n return enrichedData\n } catch (e) {\n console.error(e)\n reportError({\n apiUrl,\n error: e,\n extraInfo: { type: 'getUserBonds', bondList, chains, e },\n account: accounts.evm ?? undefined,\n })\n throw new Error('Failed to fetch user bonds')\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;AAac,SAAU,YAAY,GAAA;;IAElC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,YAAY,EAAE;IACzC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC;IACtD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC;IACtD,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,eAAe,CAAC,OAAO,CAAC;IAC1D,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC;IACtD,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,cAAc,EAAE;AAC9C,IAAA,OAAO,QAAQ,CAAC;AACd,QAAA,QAAQ,EAAE;AACR,YAAA,UAAU,CAAC,UAAU;YACrB,UAAU;YACV,UAAU;YACV,YAAY;YACZ,UAAU;YACV,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,MAAM,IAAI,IAAI;AAC/C,SAAA;AACD,QAAA,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,KAClB,YAAY,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,QAAS,EAAE,MAAM,CAAC;AAC7G,QAAA,OAAO,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,EAAE,UAAU,IAAI,UAAU,IAAI,YAAY,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,WAAW;AAClG,QAAA,eAAe,EAAE,MAAM;AACvB,QAAA,oBAAoB,EAAE,KAAK;AAC3B,QAAA,cAAc,EAAE,KAAK;AACrB,QAAA,kBAAkB,EAAE,KAAK;AACzB,QAAA,KAAK,EAAE,CAAC;AACT,KAAA,CAAC;AACJ;AAEA;AACO,MAAM,YAAY,GAAG,OAC1B,QAAmD,EACnD,QAAwC,EACxC,WAAwB,KACD;AACvB,IAAA,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,YAAY,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAa;AACvF,IAAA,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;AAC5B,IAAA,MAAM,WAAW,GAA4C,WAAW,EAAE,YAAY,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAE;AAElH,IAAA,IAAI;AACF,QAAA,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC;aACG,MAAM,CAAC,CAAC,KAAc,KAAK,QAAQ,CAAC,KAAK,CAAC;AAC1C,aAAA,GAAG,CAAC,CAAC,KAAc,KAAI;;AAEtB,YAAA,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC;YACzC,MAAM,OAAO,GAAG,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;YACtD,OAAO,OAAO,IAAI,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,GAAG,EAAE;QACvG,CAAC,CAAC,CACL;;QAGD,MAAM,gBAAgB,GAAG;aACtB,MAAM,CAAC,CAAC,MAAM,KAA4C,MAAM,CAAC,MAAM,KAAK,WAAW;aACvF,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC;AAEhC,QAAA,MAAM,WAAW,GAAe,gBAAgB,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,cAAc,CAAC;;;;AAKlG,QAAA,MAAM,YAAY,GAAG,CAAC,OAAiB,KAAK,kBAAkB,CAAC,OAAkB,CAAC,EAAE,qBAAqB,IAAI,IAAI;AACjH,QAAA,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CACxB;AACG,aAAA,MAAM,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC;AAClD,aAAA,MAAM,CACL,CAAC,GAAG,EAAE,IAAI,KAAI;AACZ,YAAA,MAAM,QAAQ,GACZ,IAAI,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,cAAc;YAC1G,MAAM,GAAG,GAAG,CAAA,EAAG,IAAI,EAAE,IAAI,EAAE,OAAO,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAE;AAEhD,YAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;gBACb,GAAG,CAAC,GAAG,CAAC,GAAG;AACT,oBAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAiB;AACtC,oBAAA,QAAQ,EAAE,QAAkB;AAC5B,oBAAA,OAAO,EAAE,EAAE;iBACZ;YACH;AAEA,YAAA,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxC,YAAA,OAAO,GAAG;AACZ,QAAA,CAAC,EACD,EAA8E,CAC/E,CACJ;AACD,QAAA,IAAI,YAAY;AAEhB,QAAA,IAAI;AACF,YAAA,YAAY,GAAG,MAAM,OAAO,CAAQ,CAAA,EAAG,MAAM,CAAA,kBAAA,CAAoB,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAChG;QAAE,OAAO,CAAC,EAAE;AACV,YAAA,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAChB,YAAA,OAAO,WAAW;QACpB;;;;QAIA,MAAM,YAAY,GAAe,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAI;YAC5D,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;AAAE,gBAAA,OAAO,QAAQ;YAE1D,MAAM,eAAe,GAAG,YAAY,EAAE,IAAI,CAAC,CAAC,GAAQ,KAAI;gBACtD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE;AAC3C,gBAAA,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO;;gBAGzB,MAAM,iBAAiB,GACrB,KAAK,KAAK,OAAO,CAAC,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,cAAc;AAC/F,gBAAA,OAAO,iBAAiB,EAAE,WAAW,EAAE,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,OAAO,KAAK,KAAK;AAC1F,YAAA,CAAC,CAAC;YACF,MAAM,OAAO,GAAgC,eAAe,EAAE,KAAK,EAAE,IAAI,CACvE,CAAC,WAA4B,KAAK,WAAW,CAAC,OAAO,KAAK,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAChF;YACD,OAAO;AACL,gBAAA,GAAG,QAAQ;gBACX,OAAO;aACR;AACH,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,YAAY;IACrB;IAAE,OAAO,CAAC,EAAE;AACV,QAAA,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAChB,QAAA,WAAW,CAAC;YACV,MAAM;AACN,YAAA,KAAK,EAAE,CAAC;YACR,SAAS,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE;AACxD,YAAA,OAAO,EAAE,QAAQ,CAAC,GAAG,IAAI,SAAS;AACnC,SAAA,CAAC;AACF,QAAA,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC;IAC/C;AACF;;;;"}
1
+ {"version":3,"file":"useUserBonds.js","sources":["../../../src/state/bonds/useUserBonds.ts"],"sourcesContent":["import { QueryClient, useQuery, UseQueryResult } from '@tanstack/react-query'\nimport { QUERY_KEYS } from '../../config/constants/queryKeys'\nimport { BillsConfig, ChainId } from '@ape.swap/apeswap-lists'\nimport useBondsList from './useBondsList'\nimport { UserBill, UserBillNftData } from '../../types/yourbonds'\nimport { SDKProps } from '../useSDKConfig'\nimport useTokenPrices, { TokenPrices } from '../tokenPrices/useTokenPrices'\nimport { reportError } from '../../utils/reportError'\nimport useChainAccount from '../chainAccount/useChainAccount'\nimport { apiPost } from '../../utils/httpClient'\nimport { getAdapterForChain } from '../../adapters/registry'\nimport type { Ecosystem } from '../../adapters/types'\n\n/** What the query caches: the bills plus the chains whose bills couldn't be fetched. */\nexport interface UserBondsResult {\n bills: UserBill[]\n /** Chains (with a registered adapter and a connected account) whose fetch failed. Their bills are missing from `bills`. */\n failedChains: ChainId[]\n}\n\nexport default function useUserBonds(): Omit<UseQueryResult<UserBondsResult>, 'data'> & {\n data: UserBill[] | undefined\n failedChains: ChainId[]\n} {\n // First fetch the full list of bonds\n const { data: bondList } = useBondsList()\n const { address: addressEVM } = useChainAccount('evm')\n const { address: addressSOL } = useChainAccount('sol')\n const { address: addressAptos } = useChainAccount('aptos')\n const { address: addressSUI } = useChainAccount('sui')\n const { data: tokenPrices } = useTokenPrices()\n const query = useQuery({\n queryKey: [\n QUERY_KEYS.USER_BONDS,\n addressEVM,\n addressSOL,\n addressAptos,\n addressSUI,\n Object.keys(tokenPrices ?? {})?.length ?? null,\n ],\n queryFn: ({ client }) =>\n fetchUserBonds({ evm: addressEVM, sol: addressSOL, aptos: addressAptos, sui: addressSUI }, bondList!, client),\n enabled: !!bondList && !!(addressEVM || addressSOL || addressAptos || addressSUI) && !!tokenPrices,\n refetchInterval: 120000,\n refetchOnWindowFocus: false,\n refetchOnMount: false,\n refetchOnReconnect: false,\n retry: 1,\n })\n // `data` stays the plain bills array for consumers; failed chains are exposed next to it\n return { ...query, data: query.data?.bills, failedChains: query.data?.failedChains ?? [] }\n}\n\n/** @param accounts the connected account of each family, by ecosystem (see useChainAccount) */\nexport const getUserBonds = async (\n accounts: Partial<Record<Ecosystem, string | null>>,\n bondList: Record<ChainId, BillsConfig[]>,\n queryClient: QueryClient,\n): Promise<UserBill[]> => (await fetchUserBonds(accounts, bondList, queryClient)).bills\n\nconst fetchUserBonds = async (\n accounts: Partial<Record<Ecosystem, string | null>>,\n bondList: Record<ChainId, BillsConfig[]>,\n queryClient: QueryClient,\n): Promise<UserBondsResult> => {\n const { chains, urls } = queryClient?.getQueryData([QUERY_KEYS.SDK_CONFIG]) as SDKProps\n const apiUrl = urls['apiV2']\n const tokenPrices: Partial<Record<ChainId, TokenPrices[]>> = queryClient?.getQueryData([QUERY_KEYS.TOKEN_PRICES])!\n\n try {\n const chainsToFetch = chains.filter((chain: ChainId) => bondList[chain])\n const results = await Promise.allSettled(\n chainsToFetch.map((chain: ChainId) => {\n // Chains without a registered adapter are unsupported\n const adapter = getAdapterForChain(chain)\n const account = adapter && accounts[adapter.ecosystem]\n return adapter && account ? adapter.fetchUserBonds(chain, account, bondList[chain], tokenPrices, apiUrl) : []\n }),\n )\n\n // `results` follows `chainsToFetch`. Chains skipped above (no adapter / no account) resolve to [], not a failure.\n const failedChains = chainsToFetch.filter((_chain: ChainId, i: number) => results[i].status === 'rejected')\n\n // Filter out only fulfilled promises\n const fulfilledResults = results\n .filter((result): result is PromiseFulfilledResult<any> => result.status === 'fulfilled')\n .map((result) => result.value)\n\n const onChainData: UserBill[] = fulfilledResults.flat().flatMap((result) => result.userOwnedBills)\n\n // Prepare body for batch API call\n // api-v2 doesn't support adapters with enrichUserBondsViaApi: false (e.g. Aptos, Sui). Their bills are read\n // on-chain, with no /bills/multi-batch enrichment, and use the placeholder image from their constants.\n const enrichViaApi = (chainId?: ChainId) => getAdapterForChain(chainId as ChainId)?.enrichUserBondsViaApi ?? true\n const body = Object.values(\n onChainData\n .filter((data) => enrichViaApi(data?.bond?.chainId))\n .reduce(\n (acc, data) => {\n const contract =\n data?.bond?.chainId === ChainId.SOL ? data.bond.contractAddress[data.bond.chainId] : data.billNftAddress\n const key = `${data?.bond?.chainId}-${contract}`\n\n if (!acc[key]) {\n acc[key] = {\n chainId: data?.bond?.chainId as number,\n contract: contract as string,\n billIds: [],\n }\n }\n\n acc[key].billIds.push(parseInt(data.id))\n return acc\n },\n {} as Record<string, { chainId: number; contract: string; billIds: number[] }>,\n ),\n )\n let responseData\n\n try {\n responseData = await apiPost<any[]>(`${apiUrl}/bills/multi-batch`, body, { timeoutMs: 40000 })\n } catch (e) {\n console.error(e)\n return { bills: onChainData, failedChains }\n }\n // Enrich on-chain data with API data.\n // Bills that weren't sent to api-v2 keep the nftData their fetcher populated instead of being overwritten with\n // undefined.\n const enrichedData: UserBill[] = onChainData.map((userBond) => {\n if (!enrichViaApi(userBond.bond?.chainId)) return userBond\n\n const nftDataResponse = responseData?.find((nft: any) => {\n const contract = nft.contract.toLowerCase()\n const chain = nft.chainId\n\n // API uses contractAddress for Solana bonds instead of NFT Address\n const contractToCompare =\n chain === ChainId.SOL ? userBond.bond?.contractAddress[ChainId.SOL] : userBond.billNftAddress\n return contractToCompare?.toLowerCase() === contract && userBond.bond?.chainId === chain\n })\n const nftData: UserBillNftData | undefined = nftDataResponse?.bills?.find(\n (billApiData: UserBillNftData) => billApiData.tokenId === parseInt(userBond.id),\n )\n return {\n ...userBond,\n nftData,\n }\n })\n\n return { bills: enrichedData, failedChains }\n } catch (e) {\n console.error(e)\n reportError({\n apiUrl,\n error: e,\n extraInfo: { type: 'getUserBonds', bondList, chains, e },\n account: accounts.evm ?? undefined,\n })\n throw new Error('Failed to fetch user bonds')\n }\n}\n"],"names":[],"mappings":"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"}