@railgun-community/waku-broadcaster-client-web 8.4.0 → 9.0.2

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 (43) hide show
  1. package/README.md +148 -26
  2. package/dist/fees/broadcaster-fee-cache.d.ts +5 -0
  3. package/dist/fees/broadcaster-fee-cache.js +71 -0
  4. package/dist/fees/broadcaster-fee-cache.js.map +1 -1
  5. package/dist/fees/handle-authorized-fees-message.d.ts +2 -0
  6. package/dist/fees/handle-authorized-fees-message.js +34 -0
  7. package/dist/fees/handle-authorized-fees-message.js.map +1 -0
  8. package/dist/fees/handle-fees-message.d.ts +1 -1
  9. package/dist/fees/handle-fees-message.js +42 -3
  10. package/dist/fees/handle-fees-message.js.map +1 -1
  11. package/dist/models/broadcaster-config.d.ts +13 -2
  12. package/dist/models/broadcaster-config.js +7 -0
  13. package/dist/models/broadcaster-config.js.map +1 -1
  14. package/dist/models/constants.d.ts +3 -1
  15. package/dist/models/constants.js +7 -11
  16. package/dist/models/constants.js.map +1 -1
  17. package/dist/models/export-models.d.ts +10 -0
  18. package/dist/models/export-models.js.map +1 -1
  19. package/dist/search/best-broadcaster.d.ts +2 -2
  20. package/dist/search/best-broadcaster.js +31 -4
  21. package/dist/search/best-broadcaster.js.map +1 -1
  22. package/dist/status/broadcaster-connection-status.js +2 -1
  23. package/dist/status/broadcaster-connection-status.js.map +1 -1
  24. package/dist/transact/broadcaster-transact-response.d.ts +1 -1
  25. package/dist/transact/broadcaster-transact-response.js.map +1 -1
  26. package/dist/transact/broadcaster-transaction.js +10 -1
  27. package/dist/transact/broadcaster-transaction.js.map +1 -1
  28. package/dist/utils/broadcaster-debug.js.map +1 -1
  29. package/dist/utils/broadcaster-util.js.map +1 -1
  30. package/dist/utils/is-defined.d.ts +1 -1
  31. package/dist/waku/waku-broadcaster-waku-core-base.d.ts +31 -0
  32. package/dist/waku/waku-broadcaster-waku-core-base.js +171 -0
  33. package/dist/waku/waku-broadcaster-waku-core-base.js.map +1 -0
  34. package/dist/waku/waku-broadcaster-waku-core.d.ts +3 -24
  35. package/dist/waku/waku-broadcaster-waku-core.js +30 -133
  36. package/dist/waku/waku-broadcaster-waku-core.js.map +1 -1
  37. package/dist/waku/waku-observers.d.ts +12 -4
  38. package/dist/waku/waku-observers.js +82 -36
  39. package/dist/waku/waku-observers.js.map +1 -1
  40. package/dist/waku-broadcaster-client.d.ts +4 -6
  41. package/dist/waku-broadcaster-client.js +22 -29
  42. package/dist/waku-broadcaster-client.js.map +1 -1
  43. package/package.json +10 -8
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/models/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AAE3D,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GAAa;IAEtD,uGAAuG;IACvG,wGAAwG;CACzG,CAAC;AAEF,MAAM,CAAC,MAAM,+BAA+B,GAAa;IAEvD,oGAAoG;IACpG,qGAAqG;CACtG,CAAC","sourcesContent":["export const WAKU_RAILGUN_PUB_SUB_TOPIC = '/waku/2/rs/0/1';\n\nexport const WAKU_RAILGUN_DEFAULT_SHARD = {\n clusterId: 0,\n shard: 1,\n};\n\nexport const WAKU_RAILGUN_DEFAULT_SHARDS = {\n clusterId: 0,\n shards: [0, 1, 2, 3, 4, 5],\n};\n\nexport const WAKU_RAILGUN_DEFAULT_PEERS_WEB: string[] = [\n // Some Websocket broadcasters (web friendly):\n '/dns4/core.rootedinprivacy.com/tcp/8000/wss/p2p/16Uiu2HAm4Ai1GzKv4EykU26ST1BPT4AHtABsYCLKrDG74GWX7D6H',\n '/dns4/fleet.rootedinprivacy.com/tcp/8000/wss/p2p/16Uiu2HAm3GnUDQhBfax298CMkZX9MBHTJ9B8GXhrbueozESUaRZP',\n];\n\nexport const WAKU_RAILGUN_DEFAULT_PEERS_NODE: string[] = [\n // Some TCP broadcasters (node friendly):\n '/dns4/core.rootedinprivacy.com/tcp/60000/p2p/16Uiu2HAm4Ai1GzKv4EykU26ST1BPT4AHtABsYCLKrDG74GWX7D6H',\n '/dns4/fleet.rootedinprivacy.com/tcp/60000/p2p/16Uiu2HAm3GnUDQhBfax298CMkZX9MBHTJ9B8GXhrbueozESUaRZP',\n];\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/models/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AAE3D,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,SAAS,EAAE,CAAC;IACZ,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,CAAC;IACV,WAAW,EAAE,0BAA0B;CACxC,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GAAa,EAEvD,CAAC;AAEF,MAAM,CAAC,MAAM,+BAA+B,GAAa,EAExD,CAAC","sourcesContent":["export const WAKU_RAILGUN_PUB_SUB_TOPIC = '/waku/2/rs/1/1';\n\nexport const WAKU_RAILGUN_DEFAULT_SHARD = {\n clusterId: 1,\n shard: 1,\n shardId: 1,\n pubsubTopic: WAKU_RAILGUN_PUB_SUB_TOPIC,\n};\n\nexport const WAKU_RAILGUN_DEFAULT_SHARDS = {\n clusterId: 1,\n shards: [0, 1, 2, 3, 4, 5],\n};\n\nexport const WAKU_RAILGUN_DEFAULT_PEERS_WEB: string[] = [\n // Some Websocket broadcasters (web friendly):\n];\n\nexport const WAKU_RAILGUN_DEFAULT_PEERS_NODE: string[] = [\n // Some TCP broadcasters (node friendly):\n];\n"]}
@@ -1,9 +1,19 @@
1
1
  import { Chain, BroadcasterConnectionStatus } from '@railgun-community/shared-models';
2
+ import type { CustomDNSConfig } from './broadcaster-config.js';
2
3
  export type BroadcasterOptions = {
4
+ trustedFeeSigner: string | string[];
3
5
  poiActiveListKeys?: string[];
4
6
  pubSubTopic?: string;
5
7
  additionalDirectPeers?: string[];
6
8
  peerDiscoveryTimeout?: number;
9
+ feeExpirationTimeout?: number;
10
+ historicalLookBackTime?: number;
11
+ useDNSDiscovery?: boolean;
12
+ useCustomDNS?: CustomDNSConfig;
13
+ broadcasterVersionRange?: {
14
+ minVersion: string;
15
+ maxVersion: string;
16
+ };
7
17
  };
8
18
  export type BroadcasterConnectionStatusCallback = (chain: Chain, status: BroadcasterConnectionStatus) => void;
9
19
  export type BroadcasterDebugger = {
@@ -1 +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"]}
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';\nimport type { CustomDNSConfig } from './broadcaster-config.js';\n\nexport type BroadcasterOptions = {\n trustedFeeSigner: string | string[];\n poiActiveListKeys?: string[];\n pubSubTopic?: string;\n additionalDirectPeers?: string[];\n peerDiscoveryTimeout?: number;\n feeExpirationTimeout?: number;\n historicalLookBackTime?: number;\n useDNSDiscovery?: boolean;\n useCustomDNS?: CustomDNSConfig,\n broadcasterVersionRange?: {\n minVersion: string;\n maxVersion: string;\n };\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"]}
@@ -1,7 +1,7 @@
1
1
  import { Chain, SelectedBroadcaster } from '@railgun-community/shared-models';
2
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[]>;
3
+ static findBroadcastersForToken(chain: Chain, tokenAddress: string, useRelayAdapt: boolean, ignoreMissingAuthorizedFee?: boolean): Optional<SelectedBroadcaster[]>;
4
+ static findAllBroadcastersForChain(chain: Chain, useRelayAdapt: boolean, ignoreMissingAuthorizedFee?: boolean): Optional<SelectedBroadcaster[]>;
5
5
  static findRandomBroadcasterForToken(chain: Chain, tokenAddress: string, useRelayAdapt: boolean, percentageThreshold: number): Optional<SelectedBroadcaster>;
6
6
  static findBestBroadcaster(chain: Chain, tokenAddress: string, useRelayAdapt: boolean): Optional<SelectedBroadcaster>;
7
7
  }
@@ -3,15 +3,16 @@ import { AddressFilter } from '../filters/address-filter.js';
3
3
  import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
4
4
  import { cachedFeeUnavailableOrExpired, shortenAddress, } from '../utils/broadcaster-util.js';
5
5
  import { isDefined } from '../utils/is-defined.js';
6
+ import { BroadcasterConfig } from '../models/broadcaster-config.js';
6
7
  const SelectedBroadcasterAscendingFee = (a, b) => {
7
8
  const feeAmount = BigInt(a.tokenFee.feePerUnitGas) - BigInt(b.tokenFee.feePerUnitGas);
8
9
  if (feeAmount === BigInt(0)) {
9
- return 0;
10
+ return b.tokenFee.reliability - a.tokenFee.reliability;
10
11
  }
11
12
  return feeAmount > BigInt(0) ? 1 : -1;
12
13
  };
13
14
  export class BroadcasterSearch {
14
- static findBroadcastersForToken(chain, tokenAddress, useRelayAdapt) {
15
+ static findBroadcastersForToken(chain, tokenAddress, useRelayAdapt, ignoreMissingAuthorizedFee = false) {
15
16
  const tokenAddressLowercase = tokenAddress.toLowerCase();
16
17
  const broadcasterTokenFees = BroadcasterFeeCache.feesForChain(chain)?.forToken[tokenAddressLowercase]
17
18
  ?.forBroadcaster;
@@ -27,6 +28,25 @@ export class BroadcasterSearch {
27
28
  .join(', ')}`);
28
29
  }
29
30
  const selectedBroadcasters = [];
31
+ const authorizedFee = BroadcasterFeeCache.getAuthorizedFee(tokenAddressLowercase);
32
+ let minFee;
33
+ let maxFee;
34
+ if (BroadcasterConfig.trustedFeeSigner) {
35
+ if (authorizedFee) {
36
+ const authorizedFeeAmount = BigInt(authorizedFee.feePerUnitGas);
37
+ const varianceLower = (authorizedFeeAmount *
38
+ BigInt(Math.round(BroadcasterConfig.authorizedFeeVariancePercentageLower * 100))) /
39
+ 100n;
40
+ const varianceUpper = (authorizedFeeAmount *
41
+ BigInt(Math.round(BroadcasterConfig.authorizedFeeVariancePercentageUpper * 100))) /
42
+ 100n;
43
+ minFee = authorizedFeeAmount - varianceLower;
44
+ maxFee = authorizedFeeAmount + varianceUpper;
45
+ }
46
+ else if (!ignoreMissingAuthorizedFee) {
47
+ return [];
48
+ }
49
+ }
30
50
  broadcasterAddresses.forEach((broadcasterAddress) => {
31
51
  const identifiers = Object.keys(broadcasterTokenFees[broadcasterAddress].forIdentifier);
32
52
  identifiers.forEach((identifier) => {
@@ -34,6 +54,12 @@ export class BroadcasterSearch {
34
54
  if (cachedFeeUnavailableOrExpired(nextCachedFee, chain, useRelayAdapt)) {
35
55
  return;
36
56
  }
57
+ if (isDefined(minFee) && isDefined(maxFee)) {
58
+ const incomingFeeAmount = BigInt(nextCachedFee.feePerUnitGas);
59
+ if (incomingFeeAmount < minFee || incomingFeeAmount > maxFee) {
60
+ return;
61
+ }
62
+ }
37
63
  const selectedBroadcaster = {
38
64
  railgunAddress: broadcasterAddress,
39
65
  tokenFee: nextCachedFee,
@@ -45,7 +71,7 @@ export class BroadcasterSearch {
45
71
  selectedBroadcasters.sort((a, b) => b.tokenFee.reliability - a.tokenFee.reliability);
46
72
  return selectedBroadcasters;
47
73
  }
48
- static findAllBroadcastersForChain(chain, useRelayAdapt) {
74
+ static findAllBroadcastersForChain(chain, useRelayAdapt, ignoreMissingAuthorizedFee = false) {
49
75
  const broadcasterTokenFees = BroadcasterFeeCache.feesForChain(chain)?.forToken;
50
76
  if (!isDefined(broadcasterTokenFees)) {
51
77
  return undefined;
@@ -53,12 +79,13 @@ export class BroadcasterSearch {
53
79
  const allTokens = Object.keys(broadcasterTokenFees);
54
80
  const selectedBroadcasters = [];
55
81
  allTokens.forEach((tokenAddress) => {
56
- const broadcastersForToken = this.findBroadcastersForToken(chain, tokenAddress, useRelayAdapt);
82
+ const broadcastersForToken = this.findBroadcastersForToken(chain, tokenAddress, useRelayAdapt, ignoreMissingAuthorizedFee);
57
83
  if (!broadcastersForToken) {
58
84
  return;
59
85
  }
60
86
  selectedBroadcasters.push(...broadcastersForToken);
61
87
  });
88
+ selectedBroadcasters.sort(SelectedBroadcasterAscendingFee);
62
89
  return selectedBroadcasters;
63
90
  }
64
91
  static findRandomBroadcasterForToken(chain, tokenAddress, useRelayAdapt, percentageThreshold) {
@@ -1 +1 @@
1
- {"version":3,"file":"best-broadcaster.js","sourceRoot":"","sources":["../../src/search/best-broadcaster.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,6BAA6B,EAC7B,cAAc,GACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,MAAM,+BAA+B,GAAG,CACtC,CAAsB,EACtB,CAAsB,EACtB,EAAE;IACF,MAAM,SAAS,GACb,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtE,IAAI,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE;QAC3B,OAAO,CAAC,CAAC;KACV;IACD,OAAO,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC,CAAC;AACF,MAAM,OAAO,iBAAiB;IAC5B,MAAM,CAAC,wBAAwB,CAC7B,KAAY,EACZ,YAAoB,EACpB,aAAsB;QAEtB,MAAM,qBAAqB,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;QACzD,MAAM,oBAAoB,GACxB,mBAAmB,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,qBAAqB,CAAC;YACtE,EAAE,cAAc,CAAC;QACrB,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,EAAE;YACpC,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,mBAAmB,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC9D,MAAM,oBAAoB,GAAG,aAAa,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACvE,IAAI,mBAAmB,CAAC,MAAM,KAAK,oBAAoB,CAAC,MAAM,EAAE;YAC9D,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,MAAM,CACjD,OAAO,CAAC,EAAE,CAAC,CAAC,oBAAoB,CAAC,QAAQ,CAAC,OAAO,CAAC,CACnD,CAAC;YACF,gBAAgB,CAAC,GAAG,CAClB,0CACE,gBAAgB,CAAC,MACnB,KAAK,gBAAgB;iBAClB,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;iBACvC,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;SACH;QAED,MAAM,oBAAoB,GAA0B,EAAE,CAAC;QAEvD,oBAAoB,CAAC,OAAO,CAAC,CAAC,kBAA0B,EAAE,EAAE;YAC1D,MAAM,WAAW,GAAa,MAAM,CAAC,IAAI,CACvC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC,aAAa,CACvD,CAAC;YACF,WAAW,CAAC,OAAO,CAAC,CAAC,UAAkB,EAAE,EAAE;gBACzC,MAAM,aAAa,GACjB,oBAAoB,CAAC,kBAAkB,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;gBACrE,IACE,6BAA6B,CAAC,aAAa,EAAE,KAAK,EAAE,aAAa,CAAC,EAClE;oBACA,OAAO;iBACR;gBACD,MAAM,mBAAmB,GAAwB;oBAC/C,cAAc,EAAE,kBAAkB;oBAClC,QAAQ,EAAE,aAAa;oBACvB,YAAY;iBACb,CAAC;gBACF,oBAAoB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,oBAAoB,CAAC,IAAI,CACvB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,CAC1D,CAAC;QACF,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,MAAM,CAAC,2BAA2B,CAChC,KAAY,EACZ,aAAsB;QAEtB,MAAM,oBAAoB,GACxB,mBAAmB,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;QACpD,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,EAAE;YACpC,OAAO,SAAS,CAAC;SAClB;QACD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACpD,MAAM,oBAAoB,GAA0B,EAAE,CAAC;QACvD,SAAS,CAAC,OAAO,CAAC,CAAC,YAAoB,EAAE,EAAE;YACzC,MAAM,oBAAoB,GAAG,IAAI,CAAC,wBAAwB,CACxD,KAAK,EACL,YAAY,EACZ,aAAa,CACd,CAAC;YACF,IAAI,CAAC,oBAAoB,EAAE;gBACzB,OAAO;aACR;YACD,oBAAoB,CAAC,IAAI,CAAC,GAAG,oBAAoB,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QACH,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,MAAM,CAAC,6BAA6B,CAClC,KAAY,EACZ,YAAoB,EACpB,aAAsB,EACtB,mBAA2B;QAE3B,MAAM,oBAAoB,GACxB,mBAAmB,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;QACpD,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,EAAE;YACpC,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,oBAAoB,GAAG,IAAI,CAAC,wBAAwB,CACxD,KAAK,EACL,YAAY,EACZ,aAAa,CACd,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,EAAE;YACpC,OAAO,SAAS,CAAC;SAClB;QACD,IAAI,oBAAoB,CAAC,MAAM,KAAK,CAAC,EAAE;YACrC,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,IAAI,CAClD,+BAA+B,CAChC,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACpE,MAAM,YAAY,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QAC5E,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,MAAM,CACpD,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,YAAY,CAC1E,CAAC;QACF,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAE5E,OAAO,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,mBAAmB,CACxB,KAAY,EACZ,YAAoB,EACpB,aAAsB;QAEtB,MAAM,oBAAoB,GACxB,mBAAmB,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;QACpD,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,EAAE;YACpC,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,oBAAoB,GAAG,IAAI,CAAC,wBAAwB,CACxD,KAAK,EACL,YAAY,EACZ,aAAa,CACd,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,EAAE;YACpC,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,IAAI,CAClD,+BAA+B,CAChC,CAAC;QAEF,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;CACF","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 selectedBroadcasters.sort(\n (a, b) => b.tokenFee.reliability - a.tokenFee.reliability,\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"]}
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';\nimport { BroadcasterConfig } from '../models/broadcaster-config.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 b.tokenFee.reliability - a.tokenFee.reliability;\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 ignoreMissingAuthorizedFee = false,\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 ${removedAddresses.length\n }: ${removedAddresses\n .map(address => shortenAddress(address))\n .join(', ')}`,\n );\n }\n\n const selectedBroadcasters: SelectedBroadcaster[] = [];\n\n const authorizedFee =\n BroadcasterFeeCache.getAuthorizedFee(tokenAddressLowercase);\n let minFee: bigint | undefined;\n let maxFee: bigint | undefined;\n\n if (BroadcasterConfig.trustedFeeSigner) {\n if (authorizedFee) {\n const authorizedFeeAmount = BigInt(authorizedFee.feePerUnitGas);\n const varianceLower =\n (authorizedFeeAmount *\n BigInt(\n Math.round(\n BroadcasterConfig.authorizedFeeVariancePercentageLower * 100,\n ),\n )) /\n 100n;\n const varianceUpper =\n (authorizedFeeAmount *\n BigInt(\n Math.round(\n BroadcasterConfig.authorizedFeeVariancePercentageUpper * 100,\n ),\n )) /\n 100n;\n minFee = authorizedFeeAmount - varianceLower;\n maxFee = authorizedFeeAmount + varianceUpper;\n } else if (!ignoreMissingAuthorizedFee) {\n return [];\n }\n }\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\n if (isDefined(minFee) && isDefined(maxFee)) {\n const incomingFeeAmount = BigInt(nextCachedFee.feePerUnitGas);\n if (incomingFeeAmount < minFee || incomingFeeAmount > maxFee) {\n return;\n }\n }\n\n const selectedBroadcaster: SelectedBroadcaster = {\n railgunAddress: broadcasterAddress,\n tokenFee: nextCachedFee,\n tokenAddress,\n };\n selectedBroadcasters.push(selectedBroadcaster);\n });\n });\n\n // selectedBroadcasters.sort(SelectedBroadcasterAscendingFee);\n selectedBroadcasters.sort(\n (a, b) => b.tokenFee.reliability - a.tokenFee.reliability,\n );\n return selectedBroadcasters;\n }\n\n static findAllBroadcastersForChain(\n chain: Chain,\n useRelayAdapt: boolean,\n ignoreMissingAuthorizedFee = false,\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 ignoreMissingAuthorizedFee,\n );\n if (!broadcastersForToken) {\n return;\n }\n selectedBroadcasters.push(...broadcastersForToken);\n });\n selectedBroadcasters.sort(SelectedBroadcasterAscendingFee);\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"]}
@@ -3,6 +3,7 @@ import { BroadcasterFeeCache } from '../fees/broadcaster-fee-cache.js';
3
3
  import { AddressFilter } from '../filters/address-filter.js';
4
4
  import { cachedFeeExpired } from '../utils/broadcaster-util.js';
5
5
  import { WakuBroadcasterWakuCore } from '../waku/waku-broadcaster-waku-core.js';
6
+ import { BroadcasterConfig } from '../models/broadcaster-config.js';
6
7
  import { isDefined } from '../utils/is-defined.js';
7
8
  export class BroadcasterStatus {
8
9
  static getBroadcasterConnectionStatus(chain) {
@@ -31,7 +32,7 @@ export class BroadcasterStatus {
31
32
  }
32
33
  static hasSubscriptionsStalled() {
33
34
  const now = Date.now();
34
- const limit = 30000;
35
+ const limit = BroadcasterConfig.feeExpirationTimeout;
35
36
  const lastSubscribed = BroadcasterFeeCache.lastSubscribedFeeMessageReceivedAt;
36
37
  if (isDefined(lastSubscribed)) {
37
38
  return now - lastSubscribed > limit;
@@ -1 +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.hasSubscriptionsStalled()) {\n BroadcasterFeeCache.lastSubscribedFeeMessageReceivedAt =\n Date.now() + 5000;\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 static hasSubscriptionsStalled() {\n const now = Date.now();\n const limit = 30_000; // 30 seconds\n const lastSubscribed =\n BroadcasterFeeCache.lastSubscribedFeeMessageReceivedAt;\n if (isDefined(lastSubscribed)) {\n return now - lastSubscribed > limit;\n }\n return false;\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"]}
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 { BroadcasterConfig } from '../models/broadcaster-config.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\n if (this.hasSubscriptionsStalled()) {\n BroadcasterFeeCache.lastSubscribedFeeMessageReceivedAt =\n Date.now() + 5000;\n return BroadcasterConnectionStatus.Disconnected;\n }\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 static hasSubscriptionsStalled() {\n const now = Date.now();\n const limit = BroadcasterConfig.feeExpirationTimeout;\n const lastSubscribed =\n BroadcasterFeeCache.lastSubscribedFeeMessageReceivedAt;\n if (isDefined(lastSubscribed)) {\n return now - lastSubscribed > limit;\n }\n return false;\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"]}
@@ -1,4 +1,4 @@
1
- import { IMessage } from '@waku/interfaces';
1
+ import { type IMessage } from '@waku/sdk';
2
2
  export type WakuTransactResponse = {
3
3
  id: string;
4
4
  txHash?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"broadcaster-transact-response.js","sourceRoot":"","sources":["../../src/transact/broadcaster-transact-response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAQnD,MAAM,OAAO,2BAA2B;IACtC,MAAM,CAAC,yBAAyB,CAAiC;IACjE,MAAM,CAAC,SAAS,CAAuB;IAEvC,MAAM,CAAC,YAAY,GAAG,CAAC,GAAe,EAAE,EAAE;QACxC,2BAA2B,CAAC,SAAS,GAAG,GAAG,CAAC;QAC5C,2BAA2B,CAAC,yBAAyB,GAAG,SAAS,CAAC;IACpE,CAAC,CAAC;IAEF,MAAM,CAAC,cAAc,GAAG,GAAG,EAAE;QAC3B,2BAA2B,CAAC,SAAS,GAAG,SAAS,CAAC;QAClD,2BAA2B,CAAC,yBAAyB,GAAG,SAAS,CAAC;IACpE,CAAC,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,OAAiB;QACxE,gBAAgB,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QACpD,IAAI,CAAC,2BAA2B,CAAC,SAAS,EAAE;YAC1C,OAAO;SACR;QACD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;YAC/B,OAAO;SACR;QACD,IAAI;YACF,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAE7C,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAEnD,CAAC;YAEF,MAAM,SAAS,GAAG,gBAAgB,CAChC,aAAa,EACb,2BAA2B,CAAC,SAAS,CACtC,CAAC;YACF,IAAI,SAAS,IAAI,IAAI,EAAE;gBACrB,OAAO;aACR;YAED,gBAAgB,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;YACtE,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;YAEhD,2BAA2B,CAAC,yBAAyB;gBACnD,SAAiC,CAAC;SACrC;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE;gBAC7B,MAAM,IAAI,KAAK,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;aAC3D;YACD,gBAAgB,CAAC,KAAK,CACpB,IAAI,KAAK,CAAC,kDAAkD,EAAE;gBAC5D,KAAK;aACN,CAAC,CACH,CAAC;SACH;IACH,CAAC","sourcesContent":["import { decryptAESGCM256 } from '@railgun-community/wallet';\nimport { IMessage } from '@waku/interfaces';\nimport { bytesToUtf8 } from '../utils/conversion.js';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport { isDefined } from '../utils/is-defined.js';\n\nexport type WakuTransactResponse = {\n id: string;\n txHash?: string;\n error?: string;\n};\n\nexport class BroadcasterTransactResponse {\n static storedTransactionResponse: Optional<WakuTransactResponse>;\n static sharedKey: Optional<Uint8Array>;\n\n static setSharedKey = (key: Uint8Array) => {\n BroadcasterTransactResponse.sharedKey = key;\n BroadcasterTransactResponse.storedTransactionResponse = undefined;\n };\n\n static clearSharedKey = () => {\n BroadcasterTransactResponse.sharedKey = undefined;\n BroadcasterTransactResponse.storedTransactionResponse = undefined;\n };\n\n static async handleBroadcasterTransactionResponseMessage(message: IMessage) {\n BroadcasterDebug.log('Transact Response received.');\n if (!BroadcasterTransactResponse.sharedKey) {\n return;\n }\n if (!isDefined(message.payload)) {\n return;\n }\n try {\n const payload = bytesToUtf8(message.payload);\n\n const { result: encryptedData } = JSON.parse(payload) as {\n result: [string, string];\n };\n\n const decrypted = decryptAESGCM256(\n encryptedData,\n BroadcasterTransactResponse.sharedKey,\n );\n if (decrypted == null) {\n return;\n }\n\n BroadcasterDebug.log('Handle Broadcaster transact-response message:');\n BroadcasterDebug.log(JSON.stringify(decrypted));\n\n BroadcasterTransactResponse.storedTransactionResponse =\n decrypted as WakuTransactResponse;\n } catch (cause) {\n if (!(cause instanceof Error)) {\n throw new Error('Unexpected non-error thrown', { cause });\n }\n BroadcasterDebug.error(\n new Error('Could not handle Broadcaster tx response message', {\n cause,\n }),\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"broadcaster-transact-response.js","sourceRoot":"","sources":["../../src/transact/broadcaster-transact-response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAQnD,MAAM,OAAO,2BAA2B;IACtC,MAAM,CAAC,yBAAyB,CAAiC;IACjE,MAAM,CAAC,SAAS,CAAuB;IAEvC,MAAM,CAAC,YAAY,GAAG,CAAC,GAAe,EAAE,EAAE;QACxC,2BAA2B,CAAC,SAAS,GAAG,GAAG,CAAC;QAC5C,2BAA2B,CAAC,yBAAyB,GAAG,SAAS,CAAC;IACpE,CAAC,CAAC;IAEF,MAAM,CAAC,cAAc,GAAG,GAAG,EAAE;QAC3B,2BAA2B,CAAC,SAAS,GAAG,SAAS,CAAC;QAClD,2BAA2B,CAAC,yBAAyB,GAAG,SAAS,CAAC;IACpE,CAAC,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,2CAA2C,CAAC,OAAiB;QACxE,gBAAgB,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QACpD,IAAI,CAAC,2BAA2B,CAAC,SAAS,EAAE,CAAC;YAC3C,OAAO;QACT,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAE7C,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAEnD,CAAC;YAEF,MAAM,SAAS,GAAG,gBAAgB,CAChC,aAAa,EACb,2BAA2B,CAAC,SAAS,CACtC,CAAC;YACF,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;YAED,gBAAgB,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;YACtE,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;YAEhD,2BAA2B,CAAC,yBAAyB;gBACnD,SAAiC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5D,CAAC;YACD,gBAAgB,CAAC,KAAK,CACpB,IAAI,KAAK,CAAC,kDAAkD,EAAE;gBAC5D,KAAK;aACN,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC","sourcesContent":["import { decryptAESGCM256 } from '@railgun-community/wallet';\nimport { type IMessage } from '@waku/sdk';\nimport { bytesToUtf8 } from '../utils/conversion.js';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport { isDefined } from '../utils/is-defined.js';\n\nexport type WakuTransactResponse = {\n id: string;\n txHash?: string;\n error?: string;\n};\n\nexport class BroadcasterTransactResponse {\n static storedTransactionResponse: Optional<WakuTransactResponse>;\n static sharedKey: Optional<Uint8Array>;\n\n static setSharedKey = (key: Uint8Array) => {\n BroadcasterTransactResponse.sharedKey = key;\n BroadcasterTransactResponse.storedTransactionResponse = undefined;\n };\n\n static clearSharedKey = () => {\n BroadcasterTransactResponse.sharedKey = undefined;\n BroadcasterTransactResponse.storedTransactionResponse = undefined;\n };\n\n static async handleBroadcasterTransactionResponseMessage(message: IMessage) {\n BroadcasterDebug.log('Transact Response received.');\n if (!BroadcasterTransactResponse.sharedKey) {\n return;\n }\n if (!isDefined(message.payload)) {\n return;\n }\n try {\n const payload = bytesToUtf8(message.payload);\n\n const { result: encryptedData } = JSON.parse(payload) as {\n result: [string, string];\n };\n\n const decrypted = decryptAESGCM256(\n encryptedData,\n BroadcasterTransactResponse.sharedKey,\n );\n if (decrypted == null) {\n return;\n }\n\n BroadcasterDebug.log('Handle Broadcaster transact-response message:');\n BroadcasterDebug.log(JSON.stringify(decrypted));\n\n BroadcasterTransactResponse.storedTransactionResponse =\n decrypted as WakuTransactResponse;\n } catch (cause) {\n if (!(cause instanceof Error)) {\n throw new Error('Unexpected non-error thrown', { cause });\n }\n BroadcasterDebug.error(\n new Error('Could not handle Broadcaster tx response message', {\n cause,\n }),\n );\n }\n }\n}\n"]}
@@ -109,7 +109,14 @@ export class BroadcasterTransaction {
109
109
  switch (broadcastRetryState) {
110
110
  case BroadcastRetryState.RetryTransact:
111
111
  BroadcasterDebug.log(`Broadcast Waku message: ${this.messageData.method} via ${this.contentTopic}`);
112
- await WakuBroadcasterWakuCore.broadcastMessage(this.messageData, this.contentTopic);
112
+ try {
113
+ await WakuBroadcasterWakuCore.broadcastMessage(this.messageData, this.contentTopic);
114
+ }
115
+ catch (err) {
116
+ if (err instanceof Error) {
117
+ BroadcasterDebug.log(`Broadcast error: ${err.message}`);
118
+ }
119
+ }
113
120
  break;
114
121
  case BroadcastRetryState.Wait:
115
122
  break;
@@ -117,6 +124,8 @@ export class BroadcasterTransaction {
117
124
  throw new Error('Request timed out.');
118
125
  }
119
126
  const pollIterations = SECONDS_PER_RETRY / POLL_DELAY_SECONDS;
127
+ const responseTopic = contentTopics.transactResponse(this.chain);
128
+ await WakuBroadcasterWakuCore.retrieveHistoricalForTopic(responseTopic);
120
129
  const response = await poll(async () => this.getTransactionResponse(), (result) => result != null, POLL_DELAY_SECONDS * 1000, pollIterations);
121
130
  if (isDefined(response)) {
122
131
  if (isDefined(response.txHash)) {
@@ -1 +1 @@
1
- {"version":3,"file":"broadcaster-transaction.js","sourceRoot":"","sources":["../../src/transact/broadcaster-transaction.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getRailgunWalletAddressData,\n encryptDataWithSharedKey,\n getCompletedTxidFromNullifiers,\n} from '@railgun-community/wallet';\nimport {\n Chain,\n EncryptDataWithSharedKeyResponse,\n poll,\n PreTransactionPOIsPerTxidLeafPerList,\n BroadcasterEncryptedMethodParams,\n BroadcasterRawParamsTransact,\n TXIDVersion,\n} from '@railgun-community/shared-models';\nimport { BroadcasterConfig } from '../models/broadcaster-config.js';\nimport { bytesToHex } from '../utils/conversion.js';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport { isDefined } from '../utils/is-defined.js';\nimport { WakuBroadcasterWakuCore } from '../waku/waku-broadcaster-waku-core.js';\nimport { contentTopics } from '../waku/waku-topics.js';\nimport {\n WakuTransactResponse,\n BroadcasterTransactResponse,\n} from './broadcaster-transact-response.js';\nimport { getAddress, isHexString } from 'ethers';\n\n//\n// Transact: Encryption Flow\n//\n// Client:\n// 1. Generates random 16 bytes: `responseKey` and adds to transact data\n// 2. Generates a `sharedKey` from a random `privkey` and the Broadcaster's `pubkey`\n// 3. Encrypts the transact data asymmetrically, using `sharedKey` (`encryptedData = encrypt(transactData, sharedKey)`)\n// 4. Includes `publicKey` and `encryptedData` in transact message\n// 5. Sends the message\n//\n// Broadcaster:\n// 1. Decrypts the `encryptedData` using Broadcaster privkey and `sharedKey` (if error, it's not addressed to us)\n// 2. Processes transaction\n// 3. Encrypts response (`txHash` or `error`) using `responseKey` (symmetric: AES-GCM-256)\n// 4. Sends back encrypted response on transact-response: {encryptedData}\n//\n// Client:\n// 1. Catches all `transact-response`'s after sending a transaction.\n// 2. Decrypts each using the `responseKey`. (If error, not addressed to us)\n// 3. After successful decryption, parses `txHash` or `error`.\n//\n\nenum BroadcastRetryState {\n RetryTransact = 'RetryTransact',\n Wait = 'Wait',\n Timeout = 'Timeout',\n}\n\ntype BroadcastMessageData = {\n method: string;\n params: BroadcasterEncryptedMethodParams;\n};\n\n// NOTE: Broadcaster default transaction-send timeout is 45 seconds.\nconst SECONDS_PER_RETRY = 2;\nconst POLL_DELAY_SECONDS = 0.1;\nconst RETRY_TRANSACTION_SECONDS = 20;\nconst POST_ALERT_TOTAL_WAITING_SECONDS = 120;\n\nexport class BroadcasterTransaction {\n private messageData: BroadcastMessageData;\n private contentTopic: string;\n private txidVersionForInputs: TXIDVersion;\n private chain: Chain;\n private nullifiers: string[];\n\n private constructor(\n encryptedDataResponse: EncryptDataWithSharedKeyResponse,\n txidVersionForInputs: TXIDVersion,\n chain: Chain,\n nullifiers: string[],\n ) {\n this.messageData = {\n method: 'transact',\n params: {\n pubkey: encryptedDataResponse.randomPubKey,\n encryptedData: encryptedDataResponse.encryptedData,\n },\n };\n this.contentTopic = contentTopics.transact(chain);\n this.txidVersionForInputs = txidVersionForInputs;\n this.chain = chain;\n this.nullifiers = nullifiers;\n BroadcasterTransactResponse.setSharedKey(encryptedDataResponse.sharedKey);\n }\n\n static async create(\n txidVersionForInputs: TXIDVersion,\n to: string,\n data: string,\n broadcasterRailgunAddress: string,\n broadcasterFeesID: string,\n chain: Chain,\n nullifiers: string[],\n overallBatchMinGasPrice: bigint,\n useRelayAdapt: boolean,\n preTransactionPOIsPerTxidLeafPerList: PreTransactionPOIsPerTxidLeafPerList,\n ): Promise<BroadcasterTransaction> {\n const encryptedDataResponse = await this.encryptTransaction(\n txidVersionForInputs,\n to,\n data,\n broadcasterRailgunAddress,\n broadcasterFeesID,\n chain,\n overallBatchMinGasPrice,\n useRelayAdapt,\n preTransactionPOIsPerTxidLeafPerList,\n );\n return new BroadcasterTransaction(\n encryptedDataResponse,\n txidVersionForInputs,\n chain,\n nullifiers,\n );\n }\n\n private static async encryptTransaction(\n txidVersionForInputs: TXIDVersion,\n to: string,\n data: string,\n broadcasterRailgunAddress: string,\n broadcasterFeesID: string,\n chain: Chain,\n overallBatchMinGasPrice: bigint,\n useRelayAdapt: boolean,\n preTransactionPOIsPerTxidLeafPerList: PreTransactionPOIsPerTxidLeafPerList,\n ): Promise<EncryptDataWithSharedKeyResponse> {\n if (!isHexString(data)) {\n throw new Error('Data field must be a hex string.');\n }\n\n const { viewingPublicKey: broadcasterViewingKey } =\n getRailgunWalletAddressData(broadcasterRailgunAddress);\n\n const transactData: BroadcasterRawParamsTransact = {\n txidVersion: txidVersionForInputs,\n to: getAddress(to),\n data,\n broadcasterViewingKey: bytesToHex(broadcasterViewingKey),\n chainID: chain.id,\n chainType: chain.type,\n minGasPrice: overallBatchMinGasPrice.toString(),\n feesID: broadcasterFeesID,\n useRelayAdapt,\n devLog: BroadcasterConfig.IS_DEV,\n minVersion: BroadcasterConfig.MINIMUM_BROADCASTER_VERSION,\n maxVersion: BroadcasterConfig.MAXIMUM_BROADCASTER_VERSION,\n preTransactionPOIsPerTxidLeafPerList,\n };\n\n const encryptedDataResponse = await encryptDataWithSharedKey(\n transactData,\n broadcasterViewingKey,\n );\n\n return encryptedDataResponse;\n }\n\n private async findMatchingNullifierTxid(): Promise<Optional<string>> {\n try {\n const { txid } = await getCompletedTxidFromNullifiers(\n this.txidVersionForInputs,\n this.chain,\n this.nullifiers,\n );\n return txid;\n } catch (cause) {\n if (!(cause instanceof Error)) {\n throw new Error('Unexpected non-error thrown', { cause });\n }\n BroadcasterDebug.error(\n new Error('Failed to find matching nullifier txid', { cause }),\n );\n return undefined;\n }\n }\n\n private async getTransactionResponse(): Promise<\n Optional<WakuTransactResponse>\n > {\n if (BroadcasterTransactResponse.storedTransactionResponse) {\n return BroadcasterTransactResponse.storedTransactionResponse;\n }\n\n const nullifiersTxid = await this.findMatchingNullifierTxid();\n if (isDefined(nullifiersTxid)) {\n return {\n id: 'nullifier-transaction',\n txHash: nullifiersTxid,\n };\n }\n\n return undefined;\n }\n\n private getBroadcastRetryState(retryNumber: number): BroadcastRetryState {\n const retrySeconds = retryNumber * SECONDS_PER_RETRY;\n if (retrySeconds <= RETRY_TRANSACTION_SECONDS) {\n return BroadcastRetryState.RetryTransact;\n }\n if (retrySeconds >= POST_ALERT_TOTAL_WAITING_SECONDS) {\n return BroadcastRetryState.Timeout;\n }\n return BroadcastRetryState.Wait;\n }\n\n async send(): Promise<string> {\n return this.broadcast();\n }\n\n private async broadcast(retryNumber = 0): Promise<string> {\n const broadcastRetryState = this.getBroadcastRetryState(retryNumber);\n switch (broadcastRetryState) {\n case BroadcastRetryState.RetryTransact:\n // 0-20 seconds.\n BroadcasterDebug.log(\n `Broadcast Waku message: ${this.messageData.method} via ${this.contentTopic}`,\n );\n await WakuBroadcasterWakuCore.broadcastMessage(\n this.messageData,\n this.contentTopic,\n );\n break;\n case BroadcastRetryState.Wait:\n // 21-60 seconds.\n // Do nothing.\n break;\n case BroadcastRetryState.Timeout:\n // Exactly 60 seconds.\n throw new Error('Request timed out.');\n }\n\n // 15 iterations (1.5 sec total, iterate every 100ms).\n const pollIterations = SECONDS_PER_RETRY / POLL_DELAY_SECONDS;\n\n const response: Optional<WakuTransactResponse> = await poll(\n async () => this.getTransactionResponse(),\n (result: Optional<WakuTransactResponse>) => result != null,\n POLL_DELAY_SECONDS * 1000,\n pollIterations,\n );\n if (isDefined(response)) {\n if (isDefined(response.txHash)) {\n BroadcasterTransactResponse.clearSharedKey();\n return response.txHash;\n }\n if (isDefined(response.error)) {\n BroadcasterDebug.log(`Broadcast error: ${response.error}`);\n BroadcasterTransactResponse.clearSharedKey();\n throw new Error('Received response error from broadcaster.', {\n cause: new Error(response.error),\n });\n }\n }\n\n // Retry.\n return this.broadcast(retryNumber + 1);\n }\n}\n"]}
1
+ {"version":3,"file":"broadcaster-transaction.js","sourceRoot":"","sources":["../../src/transact/broadcaster-transaction.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getRailgunWalletAddressData,\n encryptDataWithSharedKey,\n getCompletedTxidFromNullifiers,\n} from '@railgun-community/wallet';\nimport {\n Chain,\n EncryptDataWithSharedKeyResponse,\n poll,\n PreTransactionPOIsPerTxidLeafPerList,\n BroadcasterEncryptedMethodParams,\n BroadcasterRawParamsTransact,\n TXIDVersion,\n} from '@railgun-community/shared-models';\nimport { BroadcasterConfig } from '../models/broadcaster-config.js';\nimport { bytesToHex } from '../utils/conversion.js';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport { isDefined } from '../utils/is-defined.js';\nimport { WakuBroadcasterWakuCore } from '../waku/waku-broadcaster-waku-core.js';\nimport { contentTopics } from '../waku/waku-topics.js';\nimport {\n WakuTransactResponse,\n BroadcasterTransactResponse,\n} from './broadcaster-transact-response.js';\nimport { getAddress, isHexString } from 'ethers';\n\n//\n// Transact: Encryption Flow\n//\n// Client:\n// 1. Generates random 16 bytes: `responseKey` and adds to transact data\n// 2. Generates a `sharedKey` from a random `privkey` and the Broadcaster's `pubkey`\n// 3. Encrypts the transact data asymmetrically, using `sharedKey` (`encryptedData = encrypt(transactData, sharedKey)`)\n// 4. Includes `publicKey` and `encryptedData` in transact message\n// 5. Sends the message\n//\n// Broadcaster:\n// 1. Decrypts the `encryptedData` using Broadcaster privkey and `sharedKey` (if error, it's not addressed to us)\n// 2. Processes transaction\n// 3. Encrypts response (`txHash` or `error`) using `responseKey` (symmetric: AES-GCM-256)\n// 4. Sends back encrypted response on transact-response: {encryptedData}\n//\n// Client:\n// 1. Catches all `transact-response`'s after sending a transaction.\n// 2. Decrypts each using the `responseKey`. (If error, not addressed to us)\n// 3. After successful decryption, parses `txHash` or `error`.\n//\n\nenum BroadcastRetryState {\n RetryTransact = 'RetryTransact',\n Wait = 'Wait',\n Timeout = 'Timeout',\n}\n\ntype BroadcastMessageData = {\n method: string;\n params: BroadcasterEncryptedMethodParams;\n};\n\n// NOTE: Broadcaster default transaction-send timeout is 45 seconds.\nconst SECONDS_PER_RETRY = 2;\nconst POLL_DELAY_SECONDS = 0.1;\nconst RETRY_TRANSACTION_SECONDS = 20;\nconst POST_ALERT_TOTAL_WAITING_SECONDS = 120;\n\nexport class BroadcasterTransaction {\n private messageData: BroadcastMessageData;\n private contentTopic: string;\n private txidVersionForInputs: TXIDVersion;\n private chain: Chain;\n private nullifiers: string[];\n\n private constructor(\n encryptedDataResponse: EncryptDataWithSharedKeyResponse,\n txidVersionForInputs: TXIDVersion,\n chain: Chain,\n nullifiers: string[],\n ) {\n this.messageData = {\n method: 'transact',\n params: {\n pubkey: encryptedDataResponse.randomPubKey,\n encryptedData: encryptedDataResponse.encryptedData,\n },\n };\n this.contentTopic = contentTopics.transact(chain);\n this.txidVersionForInputs = txidVersionForInputs;\n this.chain = chain;\n this.nullifiers = nullifiers;\n BroadcasterTransactResponse.setSharedKey(encryptedDataResponse.sharedKey);\n }\n\n static async create(\n txidVersionForInputs: TXIDVersion,\n to: string,\n data: string,\n broadcasterRailgunAddress: string,\n broadcasterFeesID: string,\n chain: Chain,\n nullifiers: string[],\n overallBatchMinGasPrice: bigint,\n useRelayAdapt: boolean,\n preTransactionPOIsPerTxidLeafPerList: PreTransactionPOIsPerTxidLeafPerList,\n ): Promise<BroadcasterTransaction> {\n const encryptedDataResponse = await this.encryptTransaction(\n txidVersionForInputs,\n to,\n data,\n broadcasterRailgunAddress,\n broadcasterFeesID,\n chain,\n overallBatchMinGasPrice,\n useRelayAdapt,\n preTransactionPOIsPerTxidLeafPerList,\n );\n return new BroadcasterTransaction(\n encryptedDataResponse,\n txidVersionForInputs,\n chain,\n nullifiers,\n );\n }\n\n private static async encryptTransaction(\n txidVersionForInputs: TXIDVersion,\n to: string,\n data: string,\n broadcasterRailgunAddress: string,\n broadcasterFeesID: string,\n chain: Chain,\n overallBatchMinGasPrice: bigint,\n useRelayAdapt: boolean,\n preTransactionPOIsPerTxidLeafPerList: PreTransactionPOIsPerTxidLeafPerList,\n ): Promise<EncryptDataWithSharedKeyResponse> {\n if (!isHexString(data)) {\n throw new Error('Data field must be a hex string.');\n }\n\n const { viewingPublicKey: broadcasterViewingKey } =\n getRailgunWalletAddressData(broadcasterRailgunAddress);\n\n const transactData: BroadcasterRawParamsTransact = {\n txidVersion: txidVersionForInputs,\n to: getAddress(to),\n data,\n broadcasterViewingKey: bytesToHex(broadcasterViewingKey),\n chainID: chain.id,\n chainType: chain.type,\n minGasPrice: overallBatchMinGasPrice.toString(),\n feesID: broadcasterFeesID,\n useRelayAdapt,\n devLog: BroadcasterConfig.IS_DEV,\n minVersion: BroadcasterConfig.MINIMUM_BROADCASTER_VERSION,\n maxVersion: BroadcasterConfig.MAXIMUM_BROADCASTER_VERSION,\n preTransactionPOIsPerTxidLeafPerList,\n };\n\n const encryptedDataResponse = await encryptDataWithSharedKey(\n transactData,\n broadcasterViewingKey,\n );\n\n return encryptedDataResponse;\n }\n\n private async findMatchingNullifierTxid(): Promise<Optional<string>> {\n try {\n const { txid } = await getCompletedTxidFromNullifiers(\n this.txidVersionForInputs,\n this.chain,\n this.nullifiers,\n );\n return txid;\n } catch (cause) {\n if (!(cause instanceof Error)) {\n throw new Error('Unexpected non-error thrown', { cause });\n }\n BroadcasterDebug.error(\n new Error('Failed to find matching nullifier txid', { cause }),\n );\n return undefined;\n }\n }\n\n private async getTransactionResponse(): Promise<\n Optional<WakuTransactResponse>\n > {\n if (BroadcasterTransactResponse.storedTransactionResponse) {\n return BroadcasterTransactResponse.storedTransactionResponse;\n }\n\n const nullifiersTxid = await this.findMatchingNullifierTxid();\n if (isDefined(nullifiersTxid)) {\n return {\n id: 'nullifier-transaction',\n txHash: nullifiersTxid,\n };\n }\n\n return undefined;\n }\n\n private getBroadcastRetryState(retryNumber: number): BroadcastRetryState {\n const retrySeconds = retryNumber * SECONDS_PER_RETRY;\n if (retrySeconds <= RETRY_TRANSACTION_SECONDS) {\n return BroadcastRetryState.RetryTransact;\n }\n if (retrySeconds >= POST_ALERT_TOTAL_WAITING_SECONDS) {\n return BroadcastRetryState.Timeout;\n }\n return BroadcastRetryState.Wait;\n }\n\n async send(): Promise<string> {\n return this.broadcast();\n }\n\n private async broadcast(retryNumber = 0): Promise<string> {\n const broadcastRetryState = this.getBroadcastRetryState(retryNumber);\n switch (broadcastRetryState) {\n case BroadcastRetryState.RetryTransact:\n // 0-20 seconds.\n BroadcasterDebug.log(\n `Broadcast Waku message: ${this.messageData.method} via ${this.contentTopic}`,\n );\n try {\n await WakuBroadcasterWakuCore.broadcastMessage(\n this.messageData,\n this.contentTopic,\n );\n } catch (err) {\n if (err instanceof Error) {\n BroadcasterDebug.log(`Broadcast error: ${err.message}`);\n }\n }\n break;\n case BroadcastRetryState.Wait:\n // 21-60 seconds.\n // Do nothing.\n break;\n case BroadcastRetryState.Timeout:\n // Exactly 60 seconds.\n throw new Error('Request timed out.');\n }\n\n // 15 iterations (1.5 sec total, iterate every 100ms).\n const pollIterations = SECONDS_PER_RETRY / POLL_DELAY_SECONDS;\n\n const responseTopic = contentTopics.transactResponse(this.chain);\n await WakuBroadcasterWakuCore.retrieveHistoricalForTopic(responseTopic);\n\n const response: Optional<WakuTransactResponse> = await poll(\n async () => this.getTransactionResponse(),\n (result: Optional<WakuTransactResponse>) => result != null,\n POLL_DELAY_SECONDS * 1000,\n pollIterations,\n );\n if (isDefined(response)) {\n if (isDefined(response.txHash)) {\n BroadcasterTransactResponse.clearSharedKey();\n return response.txHash;\n }\n if (isDefined(response.error)) {\n BroadcasterDebug.log(`Broadcast error: ${response.error}`);\n BroadcasterTransactResponse.clearSharedKey();\n throw new Error('Received response error from broadcaster.', {\n cause: new Error(response.error),\n });\n }\n }\n\n // Retry.\n return this.broadcast(retryNumber + 1);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"broadcaster-debug.js","sourceRoot":"","sources":["../../src/utils/broadcaster-debug.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,gBAAgB;IACnB,MAAM,CAAC,KAAK,CAAgC;IAEpD,MAAM,CAAC,WAAW,CAAC,KAA0B;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,GAAW;QACpB,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SACrB;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,GAAU,EAAE,aAAa,GAAG,KAAK;QAC5C,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SACvB;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,aAAa,EAAE;YAErD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;SACpB;IACH,CAAC;CACF","sourcesContent":["import { BroadcasterDebugger } from '../models/export-models.js';\n\nexport class BroadcasterDebug {\n private static debug: Optional<BroadcasterDebugger>;\n\n static setDebugger(debug: BroadcasterDebugger) {\n this.debug = debug;\n }\n\n static log(msg: string) {\n if (this.debug) {\n this.debug.log(msg);\n }\n }\n\n static error(err: Error, ignoreInTests = false) {\n if (this.debug) {\n this.debug.error(err);\n }\n if (process.env.NODE_ENV === 'test' && !ignoreInTests) {\n // eslint-disable-next-line no-console\n console.error(err);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"broadcaster-debug.js","sourceRoot":"","sources":["../../src/utils/broadcaster-debug.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,gBAAgB;IACnB,MAAM,CAAC,KAAK,CAAgC;IAEpD,MAAM,CAAC,WAAW,CAAC,KAA0B;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,GAAW;QACpB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,GAAU,EAAE,aAAa,GAAG,KAAK;QAC5C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAEtD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;CACF","sourcesContent":["import { BroadcasterDebugger } from '../models/export-models.js';\n\nexport class BroadcasterDebug {\n private static debug: Optional<BroadcasterDebugger>;\n\n static setDebugger(debug: BroadcasterDebugger) {\n this.debug = debug;\n }\n\n static log(msg: string) {\n if (this.debug) {\n this.debug.log(msg);\n }\n }\n\n static error(err: Error, ignoreInTests = false) {\n if (this.debug) {\n this.debug.error(err);\n }\n if (process.env.NODE_ENV === 'test' && !ignoreInTests) {\n // eslint-disable-next-line no-console\n console.error(err);\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"broadcaster-util.js","sourceRoot":"","sources":["../../src/utils/broadcaster-util.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EACf,cAAc,GACf,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAE1C,MAAM,CAAC,MAAM,8BAA8B,GAAG,SAAS,CAAC;AAExD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAe,EAAU,EAAE;IACxD,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE;QACvB,OAAO,OAAO,CAAC;KAChB;IAED,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACzD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,cAAsB,EACtB,UAA4B,EAC5B,EAAE;IACF,MAAM,YAAY,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IACpD,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE;QACzB,OAAO,GAAG,YAAY,KAAK,UAAU,EAAE,CAAC;KACzC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,aAAqB,EAAE,EAAE;IAGxD,OAAO,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,2BAA2B,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,OAAyB,EAAE,EAAE;IACrE,OAAO,CACL,cAAc,CACZ,OAAO,IAAI,OAAO,EAClB,iBAAiB,CAAC,2BAA2B,CAC9C,GAAG,CAAC;QACL,cAAc,CACZ,OAAO,IAAI,OAAO,EAClB,iBAAiB,CAAC,2BAA2B,CAC9C,GAAG,CAAC,CACN,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,SAAyB,EACzB,KAAY,EACZ,aAAsB,EACtB,EAAE;IACF,IAAI,aAAa,EAAE;QACjB,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;QACxC,IAAI,CAAC,UAAU,EAAE;YACf,OAAO,IAAI,CAAC;SACb;QACD,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,EAAE,CAAC,CAAC;SAChD;QAED,MAAM,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QAErD,IAAI,UAAU,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;YAC1D,OAAO,IAAI,CAAC;SACb;KACF;IAED,IAAI,SAAS,CAAC,gBAAgB,KAAK,CAAC,EAAE;QAEpC,OAAO,IAAI,CAAC;KACb;IAED,IAAI,gBAAgB,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;QAC1C,OAAO,IAAI,CAAC;KACb;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC","sourcesContent":["import {\n CachedTokenFee,\n Chain,\n networkForChain,\n versionCompare,\n} from '@railgun-community/shared-models';\nimport { BroadcasterConfig } from '../models/broadcaster-config.js';\nimport { isDefined } from './is-defined.js';\n\nconst FEE_EXPIRATION_MINIMUM_MSEC = 40000;\n\nexport const DEFAULT_BROADCASTER_IDENTIFIER = 'default';\n\nexport const shortenAddress = (address: string): string => {\n if (address.length < 13) {\n return address;\n }\n // 12 chars separated by '...'\n return `${address.slice(0, 8)}...${address.slice(-4)}`;\n};\n\nexport const nameForBroadcaster = (\n railgunAddress: string,\n identifier: Optional<string>,\n) => {\n const shortAddress = shortenAddress(railgunAddress);\n if (isDefined(identifier)) {\n return `${shortAddress}: ${identifier}`;\n }\n return shortAddress;\n};\n\nexport const cachedFeeExpired = (feeExpiration: number) => {\n // Minimum of 40sec until expiration, in order to run the proof and submit.\n // If submitted after feeCacheID expires, it risks \"Bad token fee\" error from Broadcaster.\n return feeExpiration < Date.now() + FEE_EXPIRATION_MINIMUM_MSEC;\n};\n\nexport const invalidBroadcasterVersion = (version: Optional<string>) => {\n return (\n versionCompare(\n version ?? '0.0.0',\n BroadcasterConfig.MINIMUM_BROADCASTER_VERSION,\n ) < 0 ||\n versionCompare(\n version ?? '0.0.0',\n BroadcasterConfig.MAXIMUM_BROADCASTER_VERSION,\n ) > 0\n );\n};\n\nexport const cachedFeeUnavailableOrExpired = (\n cachedFee: CachedTokenFee,\n chain: Chain,\n useRelayAdapt: boolean,\n) => {\n if (useRelayAdapt) {\n const relayAdapt = cachedFee.relayAdapt;\n if (!relayAdapt) {\n return true;\n }\n const network = networkForChain(chain);\n if (!network) {\n throw new Error(`Unrecognized chain ${chain}`);\n }\n\n const expectedRelayAdapt = network.relayAdaptHistory;\n // TODO: switch back when all testing and migration to new adapt has completed.\n if (relayAdapt && !expectedRelayAdapt.includes(relayAdapt)) {\n return true;\n }\n }\n\n if (cachedFee.availableWallets === 0) {\n // No available wallets.\n return true;\n }\n\n if (cachedFeeExpired(cachedFee.expiration)) {\n return true;\n }\n\n return false;\n};\n"]}
1
+ {"version":3,"file":"broadcaster-util.js","sourceRoot":"","sources":["../../src/utils/broadcaster-util.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,EACf,cAAc,GACf,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAE1C,MAAM,CAAC,MAAM,8BAA8B,GAAG,SAAS,CAAC;AAExD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAe,EAAU,EAAE;IACxD,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACzD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,cAAsB,EACtB,UAA4B,EAC5B,EAAE;IACF,MAAM,YAAY,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IACpD,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1B,OAAO,GAAG,YAAY,KAAK,UAAU,EAAE,CAAC;IAC1C,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,aAAqB,EAAE,EAAE;IAGxD,OAAO,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,2BAA2B,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,OAAyB,EAAE,EAAE;IACrE,OAAO,CACL,cAAc,CACZ,OAAO,IAAI,OAAO,EAClB,iBAAiB,CAAC,2BAA2B,CAC9C,GAAG,CAAC;QACL,cAAc,CACZ,OAAO,IAAI,OAAO,EAClB,iBAAiB,CAAC,2BAA2B,CAC9C,GAAG,CAAC,CACN,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,SAAyB,EACzB,KAAY,EACZ,aAAsB,EACtB,EAAE;IACF,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;QACxC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,EAAE,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QAErD,IAAI,UAAU,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3D,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,IAAI,SAAS,CAAC,gBAAgB,KAAK,CAAC,EAAE,CAAC;QAErC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,gBAAgB,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC","sourcesContent":["import {\n CachedTokenFee,\n Chain,\n networkForChain,\n versionCompare,\n} from '@railgun-community/shared-models';\nimport { BroadcasterConfig } from '../models/broadcaster-config.js';\nimport { isDefined } from './is-defined.js';\n\nconst FEE_EXPIRATION_MINIMUM_MSEC = 40000;\n\nexport const DEFAULT_BROADCASTER_IDENTIFIER = 'default';\n\nexport const shortenAddress = (address: string): string => {\n if (address.length < 13) {\n return address;\n }\n // 12 chars separated by '...'\n return `${address.slice(0, 8)}...${address.slice(-4)}`;\n};\n\nexport const nameForBroadcaster = (\n railgunAddress: string,\n identifier: Optional<string>,\n) => {\n const shortAddress = shortenAddress(railgunAddress);\n if (isDefined(identifier)) {\n return `${shortAddress}: ${identifier}`;\n }\n return shortAddress;\n};\n\nexport const cachedFeeExpired = (feeExpiration: number) => {\n // Minimum of 40sec until expiration, in order to run the proof and submit.\n // If submitted after feeCacheID expires, it risks \"Bad token fee\" error from Broadcaster.\n return feeExpiration < Date.now() + FEE_EXPIRATION_MINIMUM_MSEC;\n};\n\nexport const invalidBroadcasterVersion = (version: Optional<string>) => {\n return (\n versionCompare(\n version ?? '0.0.0',\n BroadcasterConfig.MINIMUM_BROADCASTER_VERSION,\n ) < 0 ||\n versionCompare(\n version ?? '0.0.0',\n BroadcasterConfig.MAXIMUM_BROADCASTER_VERSION,\n ) > 0\n );\n};\n\nexport const cachedFeeUnavailableOrExpired = (\n cachedFee: CachedTokenFee,\n chain: Chain,\n useRelayAdapt: boolean,\n) => {\n if (useRelayAdapt) {\n const relayAdapt = cachedFee.relayAdapt;\n if (!relayAdapt) {\n return true;\n }\n const network = networkForChain(chain);\n if (!network) {\n throw new Error(`Unrecognized chain ${chain}`);\n }\n\n const expectedRelayAdapt = network.relayAdaptHistory;\n // TODO: switch back when all testing and migration to new adapt has completed.\n if (relayAdapt && !expectedRelayAdapt.includes(relayAdapt)) {\n return true;\n }\n }\n\n if (cachedFee.availableWallets === 0) {\n // No available wallets.\n return true;\n }\n\n if (cachedFeeExpired(cachedFee.expiration)) {\n return true;\n }\n\n return false;\n};\n"]}
@@ -1 +1 @@
1
- export declare const isDefined: <T>(a: T | null | undefined) => a is T;
1
+ export declare const isDefined: <T>(a: T | undefined | null) => a is T;
@@ -0,0 +1,31 @@
1
+ import { Chain } from '@railgun-community/shared-models';
2
+ import { type LightNode } from '@waku/sdk';
3
+ import { BroadcasterOptions } from '../models/index.js';
4
+ export declare abstract class WakuBroadcasterWakuCoreBase {
5
+ static hasError: boolean;
6
+ static restartCallback: () => void;
7
+ static waku: Optional<LightNode>;
8
+ protected static pubSubTopic: string;
9
+ protected static additionalDirectPeers: string[];
10
+ protected static peerDiscoveryTimeout: number;
11
+ protected static defaultShard: {
12
+ clusterId: number;
13
+ shard: number;
14
+ shardId: number;
15
+ pubsubTopic: string;
16
+ };
17
+ static restartCount: number;
18
+ static initWaku(chain: Chain): Promise<void>;
19
+ static pollHistoricalTopics(): Promise<void>;
20
+ static setWakuRestartCallback(callback: () => void): void;
21
+ static reinitWaku(chain: Chain): Promise<void>;
22
+ static setBroadcasterOptions(broadcasterOptions: BroadcasterOptions): void;
23
+ static disconnect(): Promise<void>;
24
+ protected static connect(): Promise<void>;
25
+ static getMeshPeerCount(): number;
26
+ static getPubSubPeerCount(): number;
27
+ static getLightPushPeerCount(): Promise<number>;
28
+ static getFilterPeerCount(): Promise<number>;
29
+ static broadcastMessage(data: object, topic: string): Promise<void>;
30
+ static retrieveHistoricalForTopic(topic: string): Promise<void>;
31
+ }
@@ -0,0 +1,171 @@
1
+ import { delay } from '@railgun-community/shared-models';
2
+ import { WakuObservers } from './waku-observers.js';
3
+ import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
4
+ import { utf8ToBytes } from '../utils/conversion.js';
5
+ import { isDefined } from '../utils/is-defined.js';
6
+ import { createEncoder, createDecoder, } from '@waku/sdk';
7
+ import { WAKU_RAILGUN_DEFAULT_SHARD, WAKU_RAILGUN_PUB_SUB_TOPIC, } from '../models/constants.js';
8
+ import { BroadcasterFeeCache } from '../fees/broadcaster-fee-cache.js';
9
+ import { BroadcasterConfig } from '../models/broadcaster-config.js';
10
+ export class WakuBroadcasterWakuCoreBase {
11
+ static hasError = false;
12
+ static restartCallback;
13
+ static waku;
14
+ static pubSubTopic = WAKU_RAILGUN_PUB_SUB_TOPIC;
15
+ static additionalDirectPeers = [];
16
+ static peerDiscoveryTimeout = 60000;
17
+ static defaultShard = WAKU_RAILGUN_DEFAULT_SHARD;
18
+ static restartCount = 0;
19
+ static async initWaku(chain) {
20
+ try {
21
+ await this.connect();
22
+ if (!this.waku) {
23
+ BroadcasterDebug.log('No waku instance found');
24
+ return;
25
+ }
26
+ WakuObservers.resetCurrentChain();
27
+ await WakuObservers.setObserversForChain(this.waku, chain);
28
+ this.pollHistoricalTopics();
29
+ }
30
+ catch (err) {
31
+ if (!(err instanceof Error)) {
32
+ throw err;
33
+ }
34
+ BroadcasterDebug.error(err);
35
+ throw err;
36
+ }
37
+ }
38
+ static async pollHistoricalTopics() {
39
+ BroadcasterDebug.log("Polling historical messages");
40
+ const topics = WakuObservers.getCurrentContentTopics();
41
+ for (const topic of topics) {
42
+ await this.retrieveHistoricalForTopic(topic);
43
+ }
44
+ await delay(10_000);
45
+ }
46
+ static setWakuRestartCallback(callback) {
47
+ this.restartCallback = callback;
48
+ }
49
+ static async reinitWaku(chain) {
50
+ if (isDefined(this.waku) &&
51
+ this.waku.isStarted()) {
52
+ await this.disconnect();
53
+ }
54
+ BroadcasterFeeCache.resetCache(chain);
55
+ BroadcasterDebug.log(`Reinit Waku, ${++this.restartCount}`);
56
+ await this.initWaku(chain);
57
+ if (this.restartCallback) {
58
+ this.restartCallback();
59
+ }
60
+ }
61
+ static setBroadcasterOptions(broadcasterOptions) {
62
+ BroadcasterConfig.trustedFeeSigner = broadcasterOptions.trustedFeeSigner;
63
+ if (isDefined(broadcasterOptions.pubSubTopic)) {
64
+ this.pubSubTopic = broadcasterOptions.pubSubTopic;
65
+ }
66
+ if (broadcasterOptions.additionalDirectPeers) {
67
+ this.additionalDirectPeers =
68
+ broadcasterOptions.additionalDirectPeers;
69
+ }
70
+ if (isDefined(broadcasterOptions.peerDiscoveryTimeout)) {
71
+ this.peerDiscoveryTimeout =
72
+ broadcasterOptions.peerDiscoveryTimeout;
73
+ }
74
+ if (isDefined(broadcasterOptions.feeExpirationTimeout)) {
75
+ BroadcasterConfig.feeExpirationTimeout =
76
+ broadcasterOptions.feeExpirationTimeout;
77
+ }
78
+ if (isDefined(broadcasterOptions.historicalLookBackTime)) {
79
+ BroadcasterConfig.historicalLookBackTime = broadcasterOptions.historicalLookBackTime;
80
+ }
81
+ }
82
+ static async disconnect() {
83
+ await WakuObservers.unsubscribe(this.waku);
84
+ await this.waku?.stop();
85
+ this.waku = undefined;
86
+ }
87
+ static connect() {
88
+ throw new Error("Method 'connect' must be implemented.");
89
+ }
90
+ static getMeshPeerCount() {
91
+ return 0;
92
+ }
93
+ static getPubSubPeerCount() {
94
+ return 0;
95
+ }
96
+ static async getLightPushPeerCount() {
97
+ if (!this.waku)
98
+ return 0;
99
+ return this.waku.libp2p.getConnections().length;
100
+ }
101
+ static async getFilterPeerCount() {
102
+ if (!this.waku)
103
+ return 0;
104
+ return this.waku.libp2p.getConnections().length;
105
+ }
106
+ static async broadcastMessage(data, topic) {
107
+ if (!this.waku) {
108
+ throw new Error('Waku not initialized');
109
+ }
110
+ const encoder = createEncoder({
111
+ contentTopic: topic,
112
+ routingInfo: WAKU_RAILGUN_DEFAULT_SHARD
113
+ });
114
+ const payload = utf8ToBytes(JSON.stringify(data));
115
+ const result = await this.waku.lightPush.send(encoder, {
116
+ payload,
117
+ });
118
+ if (result.failures && result.failures.length > 0) {
119
+ throw new Error(`Failed to send message: ${result.failures.map(f => f.error).join(', ')}`);
120
+ }
121
+ }
122
+ static async retrieveHistoricalForTopic(topic) {
123
+ if (!this.waku) {
124
+ return;
125
+ }
126
+ const callback = WakuObservers.getCallbackForTopic(topic);
127
+ if (!callback) {
128
+ BroadcasterDebug.log(`No callback found for topic: ${topic}`);
129
+ return;
130
+ }
131
+ const decoder = createDecoder(topic, WAKU_RAILGUN_DEFAULT_SHARD);
132
+ try {
133
+ const startTime = new Date();
134
+ startTime.setTime(Date.now() - (BroadcasterConfig.historicalLookBackTime));
135
+ const endTime = new Date(Date.now());
136
+ const options = {
137
+ includeData: true,
138
+ pubsubTopic: this.pubSubTopic,
139
+ contentTopics: [topic],
140
+ paginationForward: true,
141
+ };
142
+ const lastMessage = WakuObservers.getLastMessage(topic);
143
+ if (lastMessage) {
144
+ const cursor = this.waku.store.createCursor(lastMessage);
145
+ options.paginationCursor = cursor;
146
+ }
147
+ else {
148
+ options.timeStart = startTime;
149
+ options.timeEnd = endTime;
150
+ }
151
+ const generator = this.waku.store.queryGenerator([decoder], options);
152
+ for await (const messagesPromises of generator) {
153
+ messagesPromises.reverse();
154
+ for (const messagePromise of messagesPromises) {
155
+ if (isDefined(messagePromise)) {
156
+ const message = await messagePromise;
157
+ if (isDefined(message)) {
158
+ callback(message);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ catch (err) {
165
+ if (err instanceof Error) {
166
+ BroadcasterDebug.log(`Error retrieving historical messages: ${err.message}`);
167
+ }
168
+ }
169
+ }
170
+ }
171
+ //# sourceMappingURL=waku-broadcaster-waku-core-base.js.map