@railgun-community/waku-broadcaster-client-node 7.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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/fees/broadcaster-fee-cache.d.ts +24 -0
  4. package/dist/fees/broadcaster-fee-cache.js +81 -0
  5. package/dist/fees/broadcaster-fee-cache.js.map +1 -0
  6. package/dist/fees/handle-fees-message.d.ts +3 -0
  7. package/dist/fees/handle-fees-message.js +90 -0
  8. package/dist/fees/handle-fees-message.js.map +1 -0
  9. package/dist/filters/address-filter.d.ts +7 -0
  10. package/dist/filters/address-filter.js +21 -0
  11. package/dist/filters/address-filter.js.map +1 -0
  12. package/dist/index.d.ts +3 -0
  13. package/dist/index.js +4 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/models/broadcaster-config.d.ts +5 -0
  16. package/dist/models/broadcaster-config.js +6 -0
  17. package/dist/models/broadcaster-config.js.map +1 -0
  18. package/dist/models/constants.d.ts +3 -0
  19. package/dist/models/constants.js +10 -0
  20. package/dist/models/constants.js.map +1 -0
  21. package/dist/models/export-models.d.ts +12 -0
  22. package/dist/models/export-models.js +2 -0
  23. package/dist/models/export-models.js.map +1 -0
  24. package/dist/models/index.d.ts +1 -0
  25. package/dist/models/index.js +2 -0
  26. package/dist/models/index.js.map +1 -0
  27. package/dist/search/best-broadcaster.d.ts +7 -0
  28. package/dist/search/best-broadcaster.js +95 -0
  29. package/dist/search/best-broadcaster.js.map +1 -0
  30. package/dist/status/broadcaster-connection-status.d.ts +6 -0
  31. package/dist/status/broadcaster-connection-status.js +72 -0
  32. package/dist/status/broadcaster-connection-status.js.map +1 -0
  33. package/dist/transact/broadcaster-transact-response.d.ts +13 -0
  34. package/dist/transact/broadcaster-transact-response.js +46 -0
  35. package/dist/transact/broadcaster-transact-response.js.map +1 -0
  36. package/dist/transact/broadcaster-transaction.d.ts +16 -0
  37. package/dist/transact/broadcaster-transaction.js +136 -0
  38. package/dist/transact/broadcaster-transaction.js.map +1 -0
  39. package/dist/transact/index.d.ts +1 -0
  40. package/dist/transact/index.js +2 -0
  41. package/dist/transact/index.js.map +1 -0
  42. package/dist/utils/broadcaster-debug.d.ts +7 -0
  43. package/dist/utils/broadcaster-debug.js +20 -0
  44. package/dist/utils/broadcaster-debug.js.map +1 -0
  45. package/dist/utils/broadcaster-util.d.ts +7 -0
  46. package/dist/utils/broadcaster-util.js +49 -0
  47. package/dist/utils/broadcaster-util.js.map +1 -0
  48. package/dist/utils/conversion.d.ts +4 -0
  49. package/dist/utils/conversion.js +14 -0
  50. package/dist/utils/conversion.js.map +1 -0
  51. package/dist/utils/is-defined.d.ts +1 -0
  52. package/dist/utils/is-defined.js +4 -0
  53. package/dist/utils/is-defined.js.map +1 -0
  54. package/dist/waku/waku-broadcaster-waku-core.d.ts +22 -0
  55. package/dist/waku/waku-broadcaster-waku-core.js +166 -0
  56. package/dist/waku/waku-broadcaster-waku-core.js.map +1 -0
  57. package/dist/waku/waku-observers.d.ts +16 -0
  58. package/dist/waku/waku-observers.js +101 -0
  59. package/dist/waku/waku-observers.js.map +1 -0
  60. package/dist/waku/waku-topics.d.ts +7 -0
  61. package/dist/waku/waku-topics.js +7 -0
  62. package/dist/waku/waku-topics.js.map +1 -0
  63. package/dist/waku-broadcaster-client.d.ts +32 -0
  64. package/dist/waku-broadcaster-client.js +147 -0
  65. package/dist/waku-broadcaster-client.js.map +1 -0
  66. package/package.json +67 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022-2024 RAILGUN Project Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the “Software”), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ /Users/zy0n/github/waku-broadcaster-client/packages/common/.prettierrc.cjs
@@ -0,0 +1,24 @@
1
+ import { CachedTokenFee, Chain } from '@railgun-community/shared-models';
2
+ type BroadcasterFeeNetworkTokenBroadcasterCacheMap = {
3
+ forIdentifier: MapType<CachedTokenFee>;
4
+ };
5
+ type BroadcasterFeeNetworkTokenCacheMap = {
6
+ forBroadcaster: MapType<BroadcasterFeeNetworkTokenBroadcasterCacheMap>;
7
+ };
8
+ type BroadcasterFeeNetworkCacheMap = {
9
+ forToken: MapType<BroadcasterFeeNetworkTokenCacheMap>;
10
+ };
11
+ export type BroadcasterFeeCacheState = {
12
+ forNetwork: MapType<BroadcasterFeeNetworkCacheMap>;
13
+ };
14
+ export declare class BroadcasterFeeCache {
15
+ private static cache;
16
+ private static poiActiveListKeys;
17
+ static init(poiActiveListKeys: string[]): void;
18
+ static addTokenFees(chain: Chain, railgunAddress: string, feeExpiration: number, tokenFeeMap: MapType<CachedTokenFee>, identifier: Optional<string>, version: string, requiredPOIListKeys: string[]): void;
19
+ static resetCache(chain: Chain): void;
20
+ static feesForChain(chain: Chain): Optional<BroadcasterFeeNetworkCacheMap>;
21
+ static feesForToken(chain: Chain, tokenAddress: string): Optional<BroadcasterFeeNetworkTokenCacheMap>;
22
+ static supportsToken(chain: Chain, tokenAddress: string, useRelayAdapt: boolean): boolean;
23
+ }
24
+ export {};
@@ -0,0 +1,81 @@
1
+ import { networkForChain, } from '@railgun-community/shared-models';
2
+ import { AddressFilter } from '../filters/address-filter.js';
3
+ import { BroadcasterConfig } from '../models/broadcaster-config.js';
4
+ import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
5
+ import { nameForBroadcaster, cachedFeeExpired, DEFAULT_RELAYER_IDENTIFIER, invalidBroadcasterVersion, cachedFeeUnavailableOrExpired, } from '../utils/broadcaster-util.js';
6
+ export class BroadcasterFeeCache {
7
+ static cache = { forNetwork: {} };
8
+ static poiActiveListKeys;
9
+ static init(poiActiveListKeys) {
10
+ this.poiActiveListKeys = poiActiveListKeys;
11
+ }
12
+ static addTokenFees(chain, railgunAddress, feeExpiration, tokenFeeMap, identifier, version, requiredPOIListKeys) {
13
+ const network = networkForChain(chain);
14
+ if (!network) {
15
+ return;
16
+ }
17
+ if (!this.poiActiveListKeys) {
18
+ throw new Error('Must define active POI list keys before adding any fees.');
19
+ }
20
+ for (const listKey of requiredPOIListKeys) {
21
+ if (!this.poiActiveListKeys.includes(listKey)) {
22
+ BroadcasterDebug.log(`[Fees] Broadcaster ${railgunAddress} requires POI list key ${listKey}, which is not active.`);
23
+ return;
24
+ }
25
+ }
26
+ const broadcasterName = nameForBroadcaster(railgunAddress, identifier);
27
+ const networkName = network.name;
28
+ if (invalidBroadcasterVersion(version)) {
29
+ BroadcasterDebug.log(`[Fees] Broadcaster version ${version} invalid (req ${BroadcasterConfig.MINIMUM_RELAYER_VERSION}-${BroadcasterConfig.MAXIMUM_RELAYER_VERSION}): ${broadcasterName}`);
30
+ return;
31
+ }
32
+ if (cachedFeeExpired(feeExpiration)) {
33
+ BroadcasterDebug.log(`[Fees] Fees expired for ${networkName} (${broadcasterName})`);
34
+ return;
35
+ }
36
+ const tokenAddresses = Object.keys(tokenFeeMap);
37
+ BroadcasterDebug.log(`[Fees] Updating fees for ${networkName} (${broadcasterName}): ${tokenAddresses.length} tokens`);
38
+ this.cache.forNetwork[networkName] ??= { forToken: {} };
39
+ const tokenAddressesLowercase = tokenAddresses.map(address => address.toLowerCase());
40
+ tokenAddressesLowercase.forEach(tokenAddress => {
41
+ this.cache.forNetwork[networkName].forToken[tokenAddress] ??= {
42
+ forBroadcaster: {},
43
+ };
44
+ this.cache.forNetwork[networkName].forToken[tokenAddress].forBroadcaster[railgunAddress] ??= { forIdentifier: {} };
45
+ this.cache.forNetwork[networkName].forToken[tokenAddress].forBroadcaster[railgunAddress].forIdentifier[identifier ?? DEFAULT_RELAYER_IDENTIFIER] =
46
+ tokenFeeMap[tokenAddress];
47
+ });
48
+ }
49
+ static resetCache(chain) {
50
+ const network = networkForChain(chain);
51
+ if (!network) {
52
+ return;
53
+ }
54
+ this.cache.forNetwork ??= {};
55
+ delete this.cache.forNetwork[network.name];
56
+ }
57
+ static feesForChain(chain) {
58
+ const network = networkForChain(chain);
59
+ if (!network) {
60
+ throw new Error('Chain not found.');
61
+ }
62
+ return this.cache.forNetwork[network.name];
63
+ }
64
+ static feesForToken(chain, tokenAddress) {
65
+ return this.feesForChain(chain)?.forToken[tokenAddress.toLowerCase()];
66
+ }
67
+ static supportsToken(chain, tokenAddress, useRelayAdapt) {
68
+ const feesForToken = this.feesForToken(chain, tokenAddress);
69
+ if (!feesForToken) {
70
+ return false;
71
+ }
72
+ const railgunAddresses = Object.keys(feesForToken.forBroadcaster);
73
+ const filteredRailgunAddresses = AddressFilter.filter(railgunAddresses);
74
+ const cachedFees = filteredRailgunAddresses
75
+ .map(railgunAddress => Object.values(feesForToken.forBroadcaster[railgunAddress].forIdentifier))
76
+ .flat();
77
+ const availableUnexpiredFee = cachedFees.find(cachedFee => !cachedFeeUnavailableOrExpired(cachedFee, chain, useRelayAdapt));
78
+ return availableUnexpiredFee != null;
79
+ }
80
+ }
81
+ //# sourceMappingURL=broadcaster-fee-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcaster-fee-cache.js","sourceRoot":"","sources":["../../src/fees/broadcaster-fee-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CachedTokenFee,\n Chain,\n networkForChain,\n} from '@railgun-community/shared-models';\nimport { AddressFilter } from '../filters/address-filter.js';\nimport { BroadcasterConfig } from '../models/broadcaster-config.js';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport {\n nameForBroadcaster,\n cachedFeeExpired,\n DEFAULT_RELAYER_IDENTIFIER,\n invalidBroadcasterVersion,\n cachedFeeUnavailableOrExpired,\n} from '../utils/broadcaster-util.js';\n\n// {forNetwork: {forToken: {forBroadcaster: (fee, updatedAt)}}}\ntype BroadcasterFeeNetworkTokenBroadcasterCacheMap = {\n forIdentifier: MapType<CachedTokenFee>;\n};\ntype BroadcasterFeeNetworkTokenCacheMap = {\n forBroadcaster: MapType<BroadcasterFeeNetworkTokenBroadcasterCacheMap>;\n};\ntype BroadcasterFeeNetworkCacheMap = {\n forToken: MapType<BroadcasterFeeNetworkTokenCacheMap>;\n};\nexport type BroadcasterFeeCacheState = {\n forNetwork: MapType<BroadcasterFeeNetworkCacheMap>;\n};\n\nexport class BroadcasterFeeCache {\n private static cache: BroadcasterFeeCacheState = { forNetwork: {} };\n\n private static poiActiveListKeys: Optional<string[]>;\n\n static init(poiActiveListKeys: string[]) {\n this.poiActiveListKeys = poiActiveListKeys;\n }\n\n static addTokenFees(\n chain: Chain,\n railgunAddress: string,\n feeExpiration: number,\n tokenFeeMap: MapType<CachedTokenFee>,\n identifier: Optional<string>,\n version: string,\n requiredPOIListKeys: string[],\n ) {\n const network = networkForChain(chain);\n if (!network) {\n return;\n }\n\n if (!this.poiActiveListKeys) {\n throw new Error(\n 'Must define active POI list keys before adding any fees.',\n );\n }\n for (const listKey of requiredPOIListKeys) {\n if (!this.poiActiveListKeys.includes(listKey)) {\n BroadcasterDebug.log(\n `[Fees] Broadcaster ${railgunAddress} requires POI list key ${listKey}, which is not active.`,\n );\n return;\n }\n }\n\n const broadcasterName = nameForBroadcaster(railgunAddress, identifier);\n const networkName = network.name;\n\n if (invalidBroadcasterVersion(version)) {\n BroadcasterDebug.log(\n `[Fees] Broadcaster version ${version} invalid (req ${BroadcasterConfig.MINIMUM_RELAYER_VERSION}-${BroadcasterConfig.MAXIMUM_RELAYER_VERSION}): ${broadcasterName}`,\n );\n return;\n }\n\n if (cachedFeeExpired(feeExpiration)) {\n BroadcasterDebug.log(\n `[Fees] Fees expired for ${networkName} (${broadcasterName})`,\n );\n return;\n }\n\n const tokenAddresses = Object.keys(tokenFeeMap);\n BroadcasterDebug.log(\n `[Fees] Updating fees for ${networkName} (${broadcasterName}): ${tokenAddresses.length} tokens`,\n );\n\n this.cache.forNetwork[networkName] ??= { forToken: {} };\n\n const tokenAddressesLowercase = tokenAddresses.map(address =>\n address.toLowerCase(),\n );\n tokenAddressesLowercase.forEach(tokenAddress => {\n this.cache.forNetwork[networkName].forToken[tokenAddress] ??= {\n forBroadcaster: {},\n };\n this.cache.forNetwork[networkName].forToken[tokenAddress].forBroadcaster[\n railgunAddress\n ] ??= { forIdentifier: {} };\n\n this.cache.forNetwork[networkName].forToken[tokenAddress].forBroadcaster[\n railgunAddress\n ].forIdentifier[identifier ?? DEFAULT_RELAYER_IDENTIFIER] =\n tokenFeeMap[tokenAddress];\n });\n }\n\n static resetCache(chain: Chain) {\n const network = networkForChain(chain);\n if (!network) {\n return;\n }\n this.cache.forNetwork ??= {};\n delete this.cache.forNetwork[network.name];\n }\n\n static feesForChain(chain: Chain): Optional<BroadcasterFeeNetworkCacheMap> {\n const network = networkForChain(chain);\n if (!network) {\n throw new Error('Chain not found.');\n }\n return this.cache.forNetwork[network.name];\n }\n\n static feesForToken(\n chain: Chain,\n tokenAddress: string,\n ): Optional<BroadcasterFeeNetworkTokenCacheMap> {\n return this.feesForChain(chain)?.forToken[tokenAddress.toLowerCase()];\n }\n\n static supportsToken(\n chain: Chain,\n tokenAddress: string,\n useRelayAdapt: boolean,\n ): boolean {\n const feesForToken = this.feesForToken(chain, tokenAddress);\n if (!feesForToken) {\n return false;\n }\n\n const railgunAddresses = Object.keys(feesForToken.forBroadcaster);\n const filteredRailgunAddresses = AddressFilter.filter(railgunAddresses);\n\n const cachedFees: CachedTokenFee[] = filteredRailgunAddresses\n .map(railgunAddress =>\n Object.values(\n feesForToken.forBroadcaster[railgunAddress].forIdentifier,\n ),\n )\n .flat();\n\n const availableUnexpiredFee = cachedFees.find(\n cachedFee =>\n !cachedFeeUnavailableOrExpired(cachedFee, chain, useRelayAdapt),\n );\n return availableUnexpiredFee != null;\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { Chain } from '@railgun-community/shared-models';
2
+ import { IMessage } from '@waku/interfaces';
3
+ export declare const handleBroadcasterFeesMessage: (chain: Chain, message: IMessage, contentTopic: string) => Promise<void>;
@@ -0,0 +1,90 @@
1
+ import { verifyRelayerSignature, getRailgunWalletAddressData, } from '@railgun-community/wallet';
2
+ import crypto from 'crypto';
3
+ import { contentTopics } from '../waku/waku-topics.js';
4
+ import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
5
+ import { BroadcasterConfig } from '../models/broadcaster-config.js';
6
+ import { BroadcasterFeeCache } from './broadcaster-fee-cache.js';
7
+ import { invalidBroadcasterVersion } from '../utils/broadcaster-util.js';
8
+ import { bytesToUtf8, hexToUTF8String } from '../utils/conversion.js';
9
+ import { isDefined } from '../utils/is-defined.js';
10
+ const isExpiredTimestamp = (timestamp, expirationFeeTimestamp) => {
11
+ if (!timestamp || !expirationFeeTimestamp) {
12
+ return false;
13
+ }
14
+ let messageTimestamp = timestamp;
15
+ if (messageTimestamp.getFullYear() === 1970) {
16
+ messageTimestamp = new Date(messageTimestamp.getTime() * 1000);
17
+ }
18
+ const nowTime = Date.now();
19
+ const expirationMsec = nowTime - 45 * 1000;
20
+ const timestampExpired = messageTimestamp.getTime() < expirationMsec;
21
+ if (timestampExpired) {
22
+ BroadcasterDebug.log(`Broadcaster Fee STALE: Difference was ${(Date.now() - messageTimestamp.getTime()) / 1000}s`);
23
+ }
24
+ else {
25
+ BroadcasterDebug.log(`Broadcaster Fee receipt SUCCESS in ${(Date.now() - messageTimestamp.getTime()) / 1000}s`);
26
+ }
27
+ return timestampExpired;
28
+ };
29
+ export const handleBroadcasterFeesMessage = async (chain, message, contentTopic) => {
30
+ try {
31
+ if (!isDefined(message.payload)) {
32
+ BroadcasterDebug.log('Skipping Broadcaster fees message: NO PAYLOAD');
33
+ return;
34
+ }
35
+ if (contentTopic !== contentTopics.fees(chain)) {
36
+ BroadcasterDebug.log('Skipping Broadcaster fees message: WRONG TOPIC');
37
+ return;
38
+ }
39
+ const payload = bytesToUtf8(message.payload);
40
+ const { data, signature } = JSON.parse(payload);
41
+ const utf8String = hexToUTF8String(data);
42
+ const feeMessageData = JSON.parse(utf8String);
43
+ const feeExpirationTime = new Date(feeMessageData.feeExpiration);
44
+ if (isExpiredTimestamp(message.timestamp, feeExpirationTime)) {
45
+ BroadcasterDebug.log('Skipping fee message. Timestamp Expired.');
46
+ return;
47
+ }
48
+ if (!isDefined(crypto.subtle) && BroadcasterConfig.IS_DEV) {
49
+ BroadcasterDebug.log('Skipping Broadcaster fee validation in DEV. `crypto.subtle` does not exist (not secure: use https or localhost). ');
50
+ updateFeesForBroadcaster(chain, feeMessageData);
51
+ return;
52
+ }
53
+ if (invalidBroadcasterVersion(feeMessageData.version)) {
54
+ BroadcasterDebug.log(`Skipping Broadcaster outside version range: ${feeMessageData.version}, ${feeMessageData.railgunAddress}`);
55
+ return;
56
+ }
57
+ const { railgunAddress } = feeMessageData;
58
+ const { viewingPublicKey } = getRailgunWalletAddressData(railgunAddress);
59
+ const verified = await verifyRelayerSignature(signature, data, viewingPublicKey);
60
+ if (!verified) {
61
+ return;
62
+ }
63
+ updateFeesForBroadcaster(chain, feeMessageData);
64
+ }
65
+ catch (cause) {
66
+ if (!(cause instanceof Error)) {
67
+ throw new Error('Unexpected non-error thrown', { cause });
68
+ }
69
+ BroadcasterDebug.error(new Error('Error handling Broadcaster fees', { cause }));
70
+ }
71
+ };
72
+ const updateFeesForBroadcaster = (chain, feeMessageData) => {
73
+ const tokenFeeMap = {};
74
+ const tokenAddresses = Object.keys(feeMessageData.fees);
75
+ tokenAddresses.forEach(tokenAddress => {
76
+ const feePerUnitGas = feeMessageData.fees[tokenAddress];
77
+ if (feePerUnitGas) {
78
+ const cachedFee = {
79
+ feePerUnitGas,
80
+ expiration: feeMessageData.feeExpiration,
81
+ feesID: feeMessageData.feesID,
82
+ availableWallets: feeMessageData.availableWallets,
83
+ relayAdapt: feeMessageData.relayAdapt,
84
+ };
85
+ tokenFeeMap[tokenAddress] = cachedFee;
86
+ }
87
+ });
88
+ BroadcasterFeeCache.addTokenFees(chain, feeMessageData.railgunAddress, feeMessageData.feeExpiration, tokenFeeMap, feeMessageData.identifier, feeMessageData.version, feeMessageData.requiredPOIListKeys ?? []);
89
+ };
90
+ //# sourceMappingURL=handle-fees-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handle-fees-message.js","sourceRoot":"","sources":["../../src/fees/handle-fees-message.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n verifyRelayerSignature,\n getRailgunWalletAddressData,\n} from '@railgun-community/wallet';\nimport {\n CachedTokenFee,\n Chain,\n BroadcasterFeeMessageData,\n} from '@railgun-community/shared-models';\nimport crypto from 'crypto';\nimport { IMessage } from '@waku/interfaces';\nimport { contentTopics } from '../waku/waku-topics.js';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport { BroadcasterConfig } from '../models/broadcaster-config.js';\nimport { BroadcasterFeeCache } from './broadcaster-fee-cache.js';\nimport { invalidBroadcasterVersion } from '../utils/broadcaster-util.js';\nimport { bytesToUtf8, hexToUTF8String } from '../utils/conversion.js';\nimport { isDefined } from '../utils/is-defined.js';\n\nconst isExpiredTimestamp = (\n timestamp: Optional<Date>,\n expirationFeeTimestamp: Optional<Date>,\n) => {\n if (!timestamp || !expirationFeeTimestamp) {\n return false;\n }\n let messageTimestamp = timestamp;\n if (messageTimestamp.getFullYear() === 1970) {\n // Waku timestamp bug.\n messageTimestamp = new Date(messageTimestamp.getTime() * 1000);\n }\n // Expired if message originated > 45 seconds ago.\n // check if fee expires within 45 seconds; if it doesn't ignore it.\n const nowTime = Date.now();\n const expirationMsec = nowTime - 45 * 1000;\n // const expirationFeeMsec = nowTime + 45 * 1000;\n const timestampExpired = messageTimestamp.getTime() < expirationMsec;\n if (timestampExpired) {\n BroadcasterDebug.log(\n `Broadcaster Fee STALE: Difference was ${\n (Date.now() - messageTimestamp.getTime()) / 1000\n }s`,\n );\n } else {\n BroadcasterDebug.log(\n `Broadcaster Fee receipt SUCCESS in ${\n (Date.now() - messageTimestamp.getTime()) / 1000\n }s`,\n );\n }\n // const feeExpired = expirationFeeTimestamp.getTime() < expirationFeeMsec;\n return timestampExpired; // || feeExpired;\n};\n\nexport const handleBroadcasterFeesMessage = async (\n chain: Chain,\n message: IMessage,\n contentTopic: string,\n) => {\n try {\n if (!isDefined(message.payload)) {\n BroadcasterDebug.log('Skipping Broadcaster fees message: NO PAYLOAD');\n return;\n }\n if (contentTopic !== contentTopics.fees(chain)) {\n BroadcasterDebug.log('Skipping Broadcaster fees message: WRONG TOPIC');\n return;\n }\n const payload = bytesToUtf8(message.payload);\n const { data, signature } = JSON.parse(payload) as {\n data: string;\n signature: string;\n };\n const utf8String = hexToUTF8String(data);\n const feeMessageData = JSON.parse(utf8String) as BroadcasterFeeMessageData;\n const feeExpirationTime = new Date(feeMessageData.feeExpiration);\n if (isExpiredTimestamp(message.timestamp, feeExpirationTime)) {\n BroadcasterDebug.log('Skipping fee message. Timestamp Expired.');\n return;\n }\n\n if (!isDefined(crypto.subtle) && BroadcasterConfig.IS_DEV) {\n BroadcasterDebug.log(\n 'Skipping Broadcaster fee validation in DEV. `crypto.subtle` does not exist (not secure: use https or localhost). ',\n );\n updateFeesForBroadcaster(chain, feeMessageData);\n return;\n }\n\n if (invalidBroadcasterVersion(feeMessageData.version)) {\n BroadcasterDebug.log(\n `Skipping Broadcaster outside version range: ${feeMessageData.version}, ${feeMessageData.railgunAddress}`,\n );\n return;\n }\n\n const { railgunAddress } = feeMessageData;\n const { viewingPublicKey } = getRailgunWalletAddressData(railgunAddress);\n //TODO: rename this to verifyBroadcasterSignature\n const verified = await verifyRelayerSignature(\n signature,\n data,\n viewingPublicKey,\n );\n if (!verified) {\n return;\n }\n\n updateFeesForBroadcaster(chain, feeMessageData);\n } catch (cause) {\n if (!(cause instanceof Error)) {\n throw new Error('Unexpected non-error thrown', { cause });\n }\n\n BroadcasterDebug.error(\n new Error('Error handling Broadcaster fees', { cause }),\n );\n }\n};\n\nconst updateFeesForBroadcaster = (\n chain: Chain,\n feeMessageData: BroadcasterFeeMessageData,\n) => {\n const tokenFeeMap: MapType<CachedTokenFee> = {};\n const tokenAddresses = Object.keys(feeMessageData.fees);\n tokenAddresses.forEach(tokenAddress => {\n const feePerUnitGas = feeMessageData.fees[tokenAddress];\n if (feePerUnitGas) {\n const cachedFee: CachedTokenFee = {\n feePerUnitGas,\n expiration: feeMessageData.feeExpiration,\n feesID: feeMessageData.feesID,\n availableWallets: feeMessageData.availableWallets,\n relayAdapt: feeMessageData.relayAdapt,\n };\n tokenFeeMap[tokenAddress] = cachedFee;\n }\n });\n\n BroadcasterFeeCache.addTokenFees(\n chain,\n feeMessageData.railgunAddress,\n feeMessageData.feeExpiration,\n tokenFeeMap,\n feeMessageData.identifier,\n feeMessageData.version,\n feeMessageData.requiredPOIListKeys ?? [],\n );\n};\n"]}
@@ -0,0 +1,7 @@
1
+ export declare class AddressFilter {
2
+ private static allowlist;
3
+ private static blocklist;
4
+ static setAllowlist(allowlist: Optional<string[]>): void;
5
+ static setBlocklist(blocklist: Optional<string[]>): void;
6
+ static filter(addresses: string[]): string[];
7
+ }
@@ -0,0 +1,21 @@
1
+ export class AddressFilter {
2
+ static allowlist;
3
+ static blocklist;
4
+ static setAllowlist(allowlist) {
5
+ this.allowlist = allowlist;
6
+ }
7
+ static setBlocklist(blocklist) {
8
+ this.blocklist = blocklist;
9
+ }
10
+ static filter(addresses) {
11
+ return addresses
12
+ .filter(address => {
13
+ return !this.allowlist || this.allowlist.includes(address);
14
+ })
15
+ .filter(address => {
16
+ return !this.blocklist || !this.blocklist.includes(address);
17
+ })
18
+ .sort();
19
+ }
20
+ }
21
+ //# sourceMappingURL=address-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-filter.js","sourceRoot":"","sources":["../../src/filters/address-filter.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,aAAa;IAChB,MAAM,CAAC,SAAS,CAAqB;IACrC,MAAM,CAAC,SAAS,CAAqB;IAE7C,MAAM,CAAC,YAAY,CAAC,SAA6B;QAC/C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,SAA6B;QAC/C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,SAAmB;QAC/B,OAAO,SAAS;aACb,MAAM,CAAC,OAAO,CAAC,EAAE;YAChB,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC7D,CAAC,CAAC;aACD,MAAM,CAAC,OAAO,CAAC,EAAE;YAChB,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9D,CAAC,CAAC;aACD,IAAI,EAAE,CAAC;IACZ,CAAC;CACF","sourcesContent":["export class AddressFilter {\n private static allowlist: Optional<string[]>;\n private static blocklist: Optional<string[]>;\n\n static setAllowlist(allowlist: Optional<string[]>) {\n this.allowlist = allowlist;\n }\n\n static setBlocklist(blocklist: Optional<string[]>) {\n this.blocklist = blocklist;\n }\n\n static filter(addresses: string[]): string[] {\n return addresses\n .filter(address => {\n return !this.allowlist || this.allowlist.includes(address);\n })\n .filter(address => {\n return !this.blocklist || !this.blocklist.includes(address);\n })\n .sort();\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export * from './waku-broadcaster-client.js';
2
+ export * from './models/index.js';
3
+ export * from './transact/index.js';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './waku-broadcaster-client.js';
2
+ export * from './models/index.js';
3
+ export * from './transact/index.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC","sourcesContent":["export * from './waku-broadcaster-client.js';\nexport * from './models/index.js';\nexport * from './transact/index.js';\n"]}
@@ -0,0 +1,5 @@
1
+ export declare class BroadcasterConfig {
2
+ static IS_DEV: boolean;
3
+ static readonly MINIMUM_RELAYER_VERSION = "4.0.0";
4
+ static readonly MAXIMUM_RELAYER_VERSION = "4.999.0";
5
+ }
@@ -0,0 +1,6 @@
1
+ export class BroadcasterConfig {
2
+ static IS_DEV = false;
3
+ static MINIMUM_RELAYER_VERSION = '4.0.0';
4
+ static MAXIMUM_RELAYER_VERSION = '4.999.0';
5
+ }
6
+ //# sourceMappingURL=broadcaster-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcaster-config.js","sourceRoot":"","sources":["../../src/models/broadcaster-config.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,iBAAiB;IAC5B,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IAEtB,MAAM,CAAU,uBAAuB,GAAG,OAAO,CAAC;IAClD,MAAM,CAAU,uBAAuB,GAAG,SAAS,CAAC","sourcesContent":["export class BroadcasterConfig {\n static IS_DEV = false;\n\n static readonly MINIMUM_RELAYER_VERSION = '4.0.0';\n static readonly MAXIMUM_RELAYER_VERSION = '4.999.0';\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const WAKU_RAILGUN_PUB_SUB_TOPIC = "/waku/2/railgun-broadcaster";
2
+ export declare const WAKU_RAILGUN_DEFAULT_PEERS_WEB: string[];
3
+ export declare const WAKU_RAILGUN_DEFAULT_PEERS_NODE: string[];
@@ -0,0 +1,10 @@
1
+ export const WAKU_RAILGUN_PUB_SUB_TOPIC = '/waku/2/railgun-broadcaster';
2
+ export const WAKU_RAILGUN_DEFAULT_PEERS_WEB = [
3
+ '/dns4/teelf.wecamefromapes.com/tcp/8000/wss/p2p/16Uiu2HAkygexqAtchrhYVqLFBTXFEEZPtz8C8ZnSP6iYy1s22mfW',
4
+ '/dns4/fleet.wecamefromapes.com/tcp/8000/wss/p2p/16Uiu2HAkyCqm8368Z1Y1pvrBcQQtb66Mjj7uvyAKGdwur3uCbqfb',
5
+ ];
6
+ export const WAKU_RAILGUN_DEFAULT_PEERS_NODE = [
7
+ '/dns4/teelf.wecamefromapes.com/tcp/60000/p2p/16Uiu2HAkygexqAtchrhYVqLFBTXFEEZPtz8C8ZnSP6iYy1s22mfW',
8
+ '/dns4/fleet.wecamefromapes.com/tcp/60000/p2p/16Uiu2HAkyCqm8368Z1Y1pvrBcQQtb66Mjj7uvyAKGdwur3uCbqfb',
9
+ ];
10
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/models/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,0BAA0B,GAAG,6BAA6B,CAAC;AAExE,MAAM,CAAC,MAAM,8BAA8B,GAAa;IAEtD,uGAAuG;IACvG,uGAAuG;CACxG,CAAC;AAEF,MAAM,CAAC,MAAM,+BAA+B,GAAa;IAEvD,oGAAoG;IACpG,oGAAoG;CACrG,CAAC","sourcesContent":["export const WAKU_RAILGUN_PUB_SUB_TOPIC = '/waku/2/railgun-broadcaster';\n\nexport const WAKU_RAILGUN_DEFAULT_PEERS_WEB: string[] = [\n // Some Websocket broadcasters (web friendly):\n '/dns4/teelf.wecamefromapes.com/tcp/8000/wss/p2p/16Uiu2HAkygexqAtchrhYVqLFBTXFEEZPtz8C8ZnSP6iYy1s22mfW',\n '/dns4/fleet.wecamefromapes.com/tcp/8000/wss/p2p/16Uiu2HAkyCqm8368Z1Y1pvrBcQQtb66Mjj7uvyAKGdwur3uCbqfb',\n];\n\nexport const WAKU_RAILGUN_DEFAULT_PEERS_NODE: string[] = [\n // Some TCP broadcasters (node friendly):\n '/dns4/teelf.wecamefromapes.com/tcp/60000/p2p/16Uiu2HAkygexqAtchrhYVqLFBTXFEEZPtz8C8ZnSP6iYy1s22mfW',\n '/dns4/fleet.wecamefromapes.com/tcp/60000/p2p/16Uiu2HAkyCqm8368Z1Y1pvrBcQQtb66Mjj7uvyAKGdwur3uCbqfb',\n];\n"]}
@@ -0,0 +1,12 @@
1
+ import { Chain, BroadcasterConnectionStatus } from '@railgun-community/shared-models';
2
+ export type BroadcasterOptions = {
3
+ poiActiveListKeys?: string[];
4
+ pubSubTopic?: string;
5
+ additionalDirectPeers?: string[];
6
+ peerDiscoveryTimeout?: number;
7
+ };
8
+ export type BroadcasterConnectionStatusCallback = (chain: Chain, status: BroadcasterConnectionStatus) => void;
9
+ export type BroadcasterDebugger = {
10
+ log: (msg: string) => void;
11
+ error: (error: Error) => void;
12
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=export-models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-models.js","sourceRoot":"","sources":["../../src/models/export-models.ts"],"names":[],"mappings":"","sourcesContent":["import {\n Chain,\n BroadcasterConnectionStatus,\n} from '@railgun-community/shared-models';\n\nexport type BroadcasterOptions = {\n poiActiveListKeys?: string[];\n pubSubTopic?: string;\n additionalDirectPeers?: string[];\n peerDiscoveryTimeout?: number;\n};\n\nexport type BroadcasterConnectionStatusCallback = (\n chain: Chain,\n status: BroadcasterConnectionStatus,\n) => void;\n\nexport type BroadcasterDebugger = {\n log: (msg: string) => void;\n error: (error: Error) => void;\n};\n"]}
@@ -0,0 +1 @@
1
+ export * from './export-models.js';
@@ -0,0 +1,2 @@
1
+ export * from './export-models.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC","sourcesContent":["export * from './export-models.js';\n"]}
@@ -0,0 +1,7 @@
1
+ import { Chain, SelectedBroadcaster } from '@railgun-community/shared-models';
2
+ export declare class BroadcasterSearch {
3
+ static findBroadcastersForToken(chain: Chain, tokenAddress: string, useRelayAdapt: boolean): Optional<SelectedBroadcaster[]>;
4
+ static findAllBroadcastersForChain(chain: Chain, useRelayAdapt: boolean): Optional<SelectedBroadcaster[]>;
5
+ static findRandomBroadcasterForToken(chain: Chain, tokenAddress: string, useRelayAdapt: boolean, percentageThreshold: number): Optional<SelectedBroadcaster>;
6
+ static findBestBroadcaster(chain: Chain, tokenAddress: string, useRelayAdapt: boolean): Optional<SelectedBroadcaster>;
7
+ }
@@ -0,0 +1,95 @@
1
+ import { BroadcasterFeeCache } from '../fees/broadcaster-fee-cache.js';
2
+ import { AddressFilter } from '../filters/address-filter.js';
3
+ import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
4
+ import { cachedFeeUnavailableOrExpired, shortenAddress, } from '../utils/broadcaster-util.js';
5
+ import { isDefined } from '../utils/is-defined.js';
6
+ const SelectedBroadcasterAscendingFee = (a, b) => {
7
+ const feeAmount = BigInt(a.tokenFee.feePerUnitGas) - BigInt(b.tokenFee.feePerUnitGas);
8
+ if (feeAmount === BigInt(0)) {
9
+ return 0;
10
+ }
11
+ return feeAmount > BigInt(0) ? 1 : -1;
12
+ };
13
+ export class BroadcasterSearch {
14
+ static findBroadcastersForToken(chain, tokenAddress, useRelayAdapt) {
15
+ const tokenAddressLowercase = tokenAddress.toLowerCase();
16
+ const broadcasterTokenFees = BroadcasterFeeCache.feesForChain(chain)?.forToken[tokenAddressLowercase]
17
+ ?.forBroadcaster;
18
+ if (!isDefined(broadcasterTokenFees)) {
19
+ return undefined;
20
+ }
21
+ const unfilteredAddresses = Object.keys(broadcasterTokenFees);
22
+ const broadcasterAddresses = AddressFilter.filter(unfilteredAddresses);
23
+ if (unfilteredAddresses.length !== broadcasterAddresses.length) {
24
+ const removedAddresses = unfilteredAddresses.filter(address => !broadcasterAddresses.includes(address));
25
+ BroadcasterDebug.log(`Filtered RAILGUN broadcaster addresses ${removedAddresses.length}: ${removedAddresses
26
+ .map(address => shortenAddress(address))
27
+ .join(', ')}`);
28
+ }
29
+ const selectedBroadcasters = [];
30
+ broadcasterAddresses.forEach((broadcasterAddress) => {
31
+ const identifiers = Object.keys(broadcasterTokenFees[broadcasterAddress].forIdentifier);
32
+ identifiers.forEach((identifier) => {
33
+ const nextCachedFee = broadcasterTokenFees[broadcasterAddress].forIdentifier[identifier];
34
+ if (cachedFeeUnavailableOrExpired(nextCachedFee, chain, useRelayAdapt)) {
35
+ return;
36
+ }
37
+ const selectedBroadcaster = {
38
+ railgunAddress: broadcasterAddress,
39
+ tokenFee: nextCachedFee,
40
+ tokenAddress,
41
+ };
42
+ selectedBroadcasters.push(selectedBroadcaster);
43
+ });
44
+ });
45
+ return selectedBroadcasters;
46
+ }
47
+ static findAllBroadcastersForChain(chain, useRelayAdapt) {
48
+ const broadcasterTokenFees = BroadcasterFeeCache.feesForChain(chain)?.forToken;
49
+ if (!isDefined(broadcasterTokenFees)) {
50
+ return undefined;
51
+ }
52
+ const allTokens = Object.keys(broadcasterTokenFees);
53
+ const selectedBroadcasters = [];
54
+ allTokens.forEach((tokenAddress) => {
55
+ const broadcastersForToken = this.findBroadcastersForToken(chain, tokenAddress, useRelayAdapt);
56
+ if (!broadcastersForToken) {
57
+ return;
58
+ }
59
+ selectedBroadcasters.push(...broadcastersForToken);
60
+ });
61
+ return selectedBroadcasters;
62
+ }
63
+ static findRandomBroadcasterForToken(chain, tokenAddress, useRelayAdapt, percentageThreshold) {
64
+ const broadcasterTokenFees = BroadcasterFeeCache.feesForChain(chain)?.forToken;
65
+ if (!isDefined(broadcasterTokenFees)) {
66
+ return undefined;
67
+ }
68
+ const broadcastersForToken = this.findBroadcastersForToken(chain, tokenAddress, useRelayAdapt);
69
+ if (!isDefined(broadcastersForToken)) {
70
+ return undefined;
71
+ }
72
+ if (broadcastersForToken.length === 0) {
73
+ return undefined;
74
+ }
75
+ const sortedBroadcasters = broadcastersForToken.sort(SelectedBroadcasterAscendingFee);
76
+ const minFee = BigInt(sortedBroadcasters[0].tokenFee.feePerUnitGas);
77
+ const feeThreshold = (minFee * (100n + BigInt(percentageThreshold))) / 100n;
78
+ const eligibleBroadcasters = sortedBroadcasters.filter(broadcaster => BigInt(broadcaster.tokenFee.feePerUnitGas) <= feeThreshold);
79
+ const randomIndex = Math.floor(Math.random() * eligibleBroadcasters.length);
80
+ return eligibleBroadcasters[randomIndex];
81
+ }
82
+ static findBestBroadcaster(chain, tokenAddress, useRelayAdapt) {
83
+ const broadcasterTokenFees = BroadcasterFeeCache.feesForChain(chain)?.forToken;
84
+ if (!isDefined(broadcasterTokenFees)) {
85
+ return undefined;
86
+ }
87
+ const broadcastersForToken = this.findBroadcastersForToken(chain, tokenAddress, useRelayAdapt);
88
+ if (!isDefined(broadcastersForToken)) {
89
+ return undefined;
90
+ }
91
+ const sortedBroadcasters = broadcastersForToken.sort(SelectedBroadcasterAscendingFee);
92
+ return sortedBroadcasters[0];
93
+ }
94
+ }
95
+ //# sourceMappingURL=best-broadcaster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"best-broadcaster.js","sourceRoot":"","sources":["../../src/search/best-broadcaster.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chain, SelectedBroadcaster } from '@railgun-community/shared-models';\nimport { BroadcasterFeeCache } from '../fees/broadcaster-fee-cache.js';\nimport { AddressFilter } from '../filters/address-filter.js';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport {\n cachedFeeUnavailableOrExpired,\n shortenAddress,\n} from '../utils/broadcaster-util.js';\nimport { isDefined } from '../utils/is-defined.js';\n\nconst SelectedBroadcasterAscendingFee = (\n a: SelectedBroadcaster,\n b: SelectedBroadcaster,\n) => {\n const feeAmount =\n BigInt(a.tokenFee.feePerUnitGas) - BigInt(b.tokenFee.feePerUnitGas);\n if (feeAmount === BigInt(0)) {\n return 0;\n }\n return feeAmount > BigInt(0) ? 1 : -1;\n};\nexport class BroadcasterSearch {\n static findBroadcastersForToken(\n chain: Chain,\n tokenAddress: string,\n useRelayAdapt: boolean,\n ): Optional<SelectedBroadcaster[]> {\n const tokenAddressLowercase = tokenAddress.toLowerCase();\n const broadcasterTokenFees =\n BroadcasterFeeCache.feesForChain(chain)?.forToken[tokenAddressLowercase]\n ?.forBroadcaster;\n if (!isDefined(broadcasterTokenFees)) {\n return undefined;\n }\n\n const unfilteredAddresses = Object.keys(broadcasterTokenFees);\n const broadcasterAddresses = AddressFilter.filter(unfilteredAddresses);\n if (unfilteredAddresses.length !== broadcasterAddresses.length) {\n const removedAddresses = unfilteredAddresses.filter(\n address => !broadcasterAddresses.includes(address),\n );\n BroadcasterDebug.log(\n `Filtered RAILGUN broadcaster addresses ${\n removedAddresses.length\n }: ${removedAddresses\n .map(address => shortenAddress(address))\n .join(', ')}`,\n );\n }\n\n const selectedBroadcasters: SelectedBroadcaster[] = [];\n\n broadcasterAddresses.forEach((broadcasterAddress: string) => {\n const identifiers: string[] = Object.keys(\n broadcasterTokenFees[broadcasterAddress].forIdentifier,\n );\n identifiers.forEach((identifier: string) => {\n const nextCachedFee =\n broadcasterTokenFees[broadcasterAddress].forIdentifier[identifier];\n if (\n cachedFeeUnavailableOrExpired(nextCachedFee, chain, useRelayAdapt)\n ) {\n return;\n }\n const selectedBroadcaster: SelectedBroadcaster = {\n railgunAddress: broadcasterAddress,\n tokenFee: nextCachedFee,\n tokenAddress,\n };\n selectedBroadcasters.push(selectedBroadcaster);\n });\n });\n\n return selectedBroadcasters;\n }\n\n static findAllBroadcastersForChain(\n chain: Chain,\n useRelayAdapt: boolean,\n ): Optional<SelectedBroadcaster[]> {\n const broadcasterTokenFees =\n BroadcasterFeeCache.feesForChain(chain)?.forToken;\n if (!isDefined(broadcasterTokenFees)) {\n return undefined;\n }\n const allTokens = Object.keys(broadcasterTokenFees);\n const selectedBroadcasters: SelectedBroadcaster[] = [];\n allTokens.forEach((tokenAddress: string) => {\n const broadcastersForToken = this.findBroadcastersForToken(\n chain,\n tokenAddress,\n useRelayAdapt,\n );\n if (!broadcastersForToken) {\n return;\n }\n selectedBroadcasters.push(...broadcastersForToken);\n });\n return selectedBroadcasters;\n }\n\n static findRandomBroadcasterForToken(\n chain: Chain,\n tokenAddress: string,\n useRelayAdapt: boolean,\n percentageThreshold: number,\n ): Optional<SelectedBroadcaster> {\n const broadcasterTokenFees =\n BroadcasterFeeCache.feesForChain(chain)?.forToken;\n if (!isDefined(broadcasterTokenFees)) {\n return undefined;\n }\n\n const broadcastersForToken = this.findBroadcastersForToken(\n chain,\n tokenAddress,\n useRelayAdapt,\n );\n if (!isDefined(broadcastersForToken)) {\n return undefined;\n }\n if (broadcastersForToken.length === 0) {\n return undefined;\n }\n\n const sortedBroadcasters = broadcastersForToken.sort(\n SelectedBroadcasterAscendingFee,\n );\n\n const minFee = BigInt(sortedBroadcasters[0].tokenFee.feePerUnitGas);\n const feeThreshold = (minFee * (100n + BigInt(percentageThreshold))) / 100n;\n const eligibleBroadcasters = sortedBroadcasters.filter(\n broadcaster => BigInt(broadcaster.tokenFee.feePerUnitGas) <= feeThreshold,\n );\n const randomIndex = Math.floor(Math.random() * eligibleBroadcasters.length);\n\n return eligibleBroadcasters[randomIndex];\n }\n\n static findBestBroadcaster(\n chain: Chain,\n tokenAddress: string,\n useRelayAdapt: boolean,\n ): Optional<SelectedBroadcaster> {\n const broadcasterTokenFees =\n BroadcasterFeeCache.feesForChain(chain)?.forToken;\n if (!isDefined(broadcasterTokenFees)) {\n return undefined;\n }\n\n const broadcastersForToken = this.findBroadcastersForToken(\n chain,\n tokenAddress,\n useRelayAdapt,\n );\n if (!isDefined(broadcastersForToken)) {\n return undefined;\n }\n\n const sortedBroadcasters = broadcastersForToken.sort(\n SelectedBroadcasterAscendingFee,\n );\n\n return sortedBroadcasters[0];\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import { Chain, BroadcasterConnectionStatus } from '@railgun-community/shared-models';
2
+ export declare class BroadcasterStatus {
3
+ static getBroadcasterConnectionStatus(chain: Chain): BroadcasterConnectionStatus;
4
+ private static hasBroadcasterFeesForNetwork;
5
+ private static getAggregatedInfoForBroadcasters;
6
+ }
@@ -0,0 +1,72 @@
1
+ import { BroadcasterConnectionStatus, } from '@railgun-community/shared-models';
2
+ import { BroadcasterFeeCache } from '../fees/broadcaster-fee-cache.js';
3
+ import { AddressFilter } from '../filters/address-filter.js';
4
+ import { cachedFeeExpired } from '../utils/broadcaster-util.js';
5
+ import { WakuBroadcasterWakuCore } from '../waku/waku-broadcaster-waku-core.js';
6
+ import { isDefined } from '../utils/is-defined.js';
7
+ export class BroadcasterStatus {
8
+ static getBroadcasterConnectionStatus(chain) {
9
+ if (WakuBroadcasterWakuCore.hasError) {
10
+ return BroadcasterConnectionStatus.Error;
11
+ }
12
+ if (!WakuBroadcasterWakuCore.waku) {
13
+ return BroadcasterConnectionStatus.Disconnected;
14
+ }
15
+ if (!this.hasBroadcasterFeesForNetwork(chain)) {
16
+ return BroadcasterConnectionStatus.Searching;
17
+ }
18
+ const { allBroadcasterFeesExpired, anyBroadcastersAvailable } = this.getAggregatedInfoForBroadcasters(chain);
19
+ if (allBroadcasterFeesExpired) {
20
+ return BroadcasterConnectionStatus.Disconnected;
21
+ }
22
+ if (!anyBroadcastersAvailable) {
23
+ return BroadcasterConnectionStatus.AllUnavailable;
24
+ }
25
+ return BroadcasterConnectionStatus.Connected;
26
+ }
27
+ static hasBroadcasterFeesForNetwork(chain) {
28
+ const broadcasterFees = BroadcasterFeeCache.feesForChain(chain);
29
+ if (!isDefined(broadcasterFees) || !isDefined(broadcasterFees.forToken)) {
30
+ return false;
31
+ }
32
+ const cachedTokenBroadcasters = Object.values(broadcasterFees.forToken);
33
+ return (cachedTokenBroadcasters.find(tokenBroadcasterMap => {
34
+ const unfilteredBroadcasterAddresses = Object.keys(tokenBroadcasterMap.forBroadcaster);
35
+ const filteredBroadcasterAddresses = AddressFilter.filter(unfilteredBroadcasterAddresses);
36
+ return filteredBroadcasterAddresses.length > 0;
37
+ }) != null);
38
+ }
39
+ static getAggregatedInfoForBroadcasters(chain) {
40
+ const broadcasterFees = BroadcasterFeeCache.feesForChain(chain);
41
+ if (!isDefined(broadcasterFees) || !isDefined(broadcasterFees.forToken)) {
42
+ return {
43
+ allBroadcasterFeesExpired: false,
44
+ anyBroadcastersAvailable: false,
45
+ };
46
+ }
47
+ const cachedTokenBroadcasters = Object.values(broadcasterFees.forToken);
48
+ let allBroadcasterFeesExpired = true;
49
+ let anyBroadcastersAvailable = false;
50
+ cachedTokenBroadcasters.forEach(tokenBroadcasterMap => {
51
+ const unfilteredRailgunAddresses = Object.keys(tokenBroadcasterMap.forBroadcaster);
52
+ const filteredRailgunAddresses = AddressFilter.filter(unfilteredRailgunAddresses);
53
+ filteredRailgunAddresses.forEach(railgunAddress => {
54
+ const identifiers = Object.keys(tokenBroadcasterMap.forBroadcaster[railgunAddress].forIdentifier);
55
+ identifiers.every(identifier => {
56
+ const tokenFee = tokenBroadcasterMap.forBroadcaster[railgunAddress].forIdentifier[identifier];
57
+ if (cachedFeeExpired(tokenFee.expiration)) {
58
+ return true;
59
+ }
60
+ allBroadcasterFeesExpired = false;
61
+ if (tokenFee.availableWallets > 0) {
62
+ anyBroadcastersAvailable = true;
63
+ return false;
64
+ }
65
+ return true;
66
+ });
67
+ });
68
+ });
69
+ return { allBroadcasterFeesExpired, anyBroadcastersAvailable };
70
+ }
71
+ }
72
+ //# sourceMappingURL=broadcaster-connection-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcaster-connection-status.js","sourceRoot":"","sources":["../../src/status/broadcaster-connection-status.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CachedTokenFee,\n Chain,\n BroadcasterConnectionStatus,\n} from '@railgun-community/shared-models';\nimport { BroadcasterFeeCache } from '../fees/broadcaster-fee-cache.js';\nimport { AddressFilter } from '../filters/address-filter.js';\nimport { cachedFeeExpired } from '../utils/broadcaster-util.js';\nimport { WakuBroadcasterWakuCore } from '../waku/waku-broadcaster-waku-core.js';\nimport { isDefined } from '../utils/is-defined.js';\n\nexport class BroadcasterStatus {\n static getBroadcasterConnectionStatus(\n chain: Chain,\n ): BroadcasterConnectionStatus {\n if (WakuBroadcasterWakuCore.hasError) {\n return BroadcasterConnectionStatus.Error;\n }\n if (!WakuBroadcasterWakuCore.waku) {\n return BroadcasterConnectionStatus.Disconnected;\n }\n if (!this.hasBroadcasterFeesForNetwork(chain)) {\n return BroadcasterConnectionStatus.Searching;\n }\n\n const { allBroadcasterFeesExpired, anyBroadcastersAvailable } =\n this.getAggregatedInfoForBroadcasters(chain);\n if (allBroadcasterFeesExpired) {\n return BroadcasterConnectionStatus.Disconnected;\n }\n if (!anyBroadcastersAvailable) {\n return BroadcasterConnectionStatus.AllUnavailable;\n }\n\n return BroadcasterConnectionStatus.Connected;\n }\n\n private static hasBroadcasterFeesForNetwork(chain: Chain) {\n const broadcasterFees = BroadcasterFeeCache.feesForChain(chain);\n if (!isDefined(broadcasterFees) || !isDefined(broadcasterFees.forToken)) {\n return false;\n }\n\n const cachedTokenBroadcasters = Object.values(broadcasterFees.forToken);\n\n return (\n cachedTokenBroadcasters.find(tokenBroadcasterMap => {\n const unfilteredBroadcasterAddresses = Object.keys(\n tokenBroadcasterMap.forBroadcaster,\n );\n const filteredBroadcasterAddresses = AddressFilter.filter(\n unfilteredBroadcasterAddresses,\n );\n return filteredBroadcasterAddresses.length > 0;\n }) != null\n );\n }\n\n private static getAggregatedInfoForBroadcasters(chain: Chain) {\n const broadcasterFees = BroadcasterFeeCache.feesForChain(chain);\n if (!isDefined(broadcasterFees) || !isDefined(broadcasterFees.forToken)) {\n return {\n allBroadcasterFeesExpired: false,\n anyBroadcastersAvailable: false,\n };\n }\n\n const cachedTokenBroadcasters = Object.values(broadcasterFees.forToken);\n\n let allBroadcasterFeesExpired = true;\n let anyBroadcastersAvailable = false;\n\n cachedTokenBroadcasters.forEach(tokenBroadcasterMap => {\n const unfilteredRailgunAddresses = Object.keys(\n tokenBroadcasterMap.forBroadcaster,\n );\n const filteredRailgunAddresses = AddressFilter.filter(\n unfilteredRailgunAddresses,\n );\n filteredRailgunAddresses.forEach(railgunAddress => {\n const identifiers: string[] = Object.keys(\n tokenBroadcasterMap.forBroadcaster[railgunAddress].forIdentifier,\n );\n\n // Loops until we hit `return false`.\n identifiers.every(identifier => {\n const tokenFee: CachedTokenFee =\n tokenBroadcasterMap.forBroadcaster[railgunAddress].forIdentifier[\n identifier\n ];\n if (cachedFeeExpired(tokenFee.expiration)) {\n return true; // continue\n }\n\n // Any unexpired means we didn't time out.\n allBroadcasterFeesExpired = false;\n\n if (tokenFee.availableWallets > 0) {\n anyBroadcastersAvailable = true;\n return false; // break\n }\n return true; //continue\n });\n });\n });\n\n return { allBroadcasterFeesExpired, anyBroadcastersAvailable };\n }\n}\n"]}