@railgun-community/waku-broadcaster-client-web 8.3.0 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -26
- package/dist/fees/broadcaster-fee-cache.d.ts +3 -0
- package/dist/fees/broadcaster-fee-cache.js +12 -0
- package/dist/fees/broadcaster-fee-cache.js.map +1 -1
- package/dist/fees/handle-authorized-fees-message.d.ts +2 -0
- package/dist/fees/handle-authorized-fees-message.js +39 -0
- package/dist/fees/handle-authorized-fees-message.js.map +1 -0
- package/dist/fees/handle-fees-message.d.ts +1 -1
- package/dist/fees/handle-fees-message.js +34 -3
- package/dist/fees/handle-fees-message.js.map +1 -1
- package/dist/models/broadcaster-config.d.ts +12 -2
- package/dist/models/broadcaster-config.js +6 -0
- package/dist/models/broadcaster-config.js.map +1 -1
- package/dist/models/constants.d.ts +3 -1
- package/dist/models/constants.js +7 -11
- package/dist/models/constants.js.map +1 -1
- package/dist/models/export-models.d.ts +9 -0
- package/dist/models/export-models.js.map +1 -1
- package/dist/search/best-broadcaster.d.ts +2 -2
- package/dist/search/best-broadcaster.js +31 -4
- package/dist/search/best-broadcaster.js.map +1 -1
- package/dist/status/broadcaster-connection-status.js +2 -1
- package/dist/status/broadcaster-connection-status.js.map +1 -1
- package/dist/transact/broadcaster-transact-response.d.ts +1 -1
- package/dist/transact/broadcaster-transact-response.js.map +1 -1
- package/dist/transact/broadcaster-transaction.js +10 -1
- package/dist/transact/broadcaster-transaction.js.map +1 -1
- package/dist/utils/broadcaster-debug.js.map +1 -1
- package/dist/utils/broadcaster-util.js.map +1 -1
- package/dist/utils/is-defined.d.ts +1 -1
- package/dist/waku/waku-broadcaster-waku-core-base.d.ts +31 -0
- package/dist/waku/waku-broadcaster-waku-core-base.js +168 -0
- package/dist/waku/waku-broadcaster-waku-core-base.js.map +1 -0
- package/dist/waku/waku-broadcaster-waku-core.d.ts +3 -24
- package/dist/waku/waku-broadcaster-waku-core.js +30 -133
- package/dist/waku/waku-broadcaster-waku-core.js.map +1 -1
- package/dist/waku/waku-observers.d.ts +12 -4
- package/dist/waku/waku-observers.js +82 -36
- package/dist/waku/waku-observers.js.map +1 -1
- package/dist/waku-broadcaster-client.d.ts +4 -6
- package/dist/waku-broadcaster-client.js +22 -29
- package/dist/waku-broadcaster-client.js.map +1 -1
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -1,29 +1,140 @@
|
|
|
1
|
-
# RAILGUN Broadcaster Client
|
|
1
|
+
# RAILGUN Broadcaster Client (Web)
|
|
2
2
|
|
|
3
|
-
This package is
|
|
3
|
+
The **Browser/Web** specific package for the RAILGUN Broadcaster Client. This package is designed to run in client-side applications (dApps, wallets) that run in a web browser.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
yarn add @railgun-community/waku-broadcaster-client-web
|
|
9
|
+
# or
|
|
10
|
+
npm install @railgun-community/waku-broadcaster-client-web
|
|
11
|
+
```
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### 1. Initialization
|
|
16
|
+
|
|
17
|
+
Initialize the client to connect to the Waku network. In a browser environment, this typically uses WebSocket connections.
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { WakuBroadcasterClient } from '@railgun-community/waku-broadcaster-client-web';
|
|
21
|
+
import { Chain } from '@railgun-community/shared-models';
|
|
22
|
+
|
|
23
|
+
const chain: Chain = { type: 0, id: 1 }; // Ethereum Mainnet
|
|
24
|
+
|
|
25
|
+
const broadcasterOptions = {
|
|
26
|
+
// Required: Trusted Fee Signer
|
|
27
|
+
trustedFeeSigner: '0zk1...',
|
|
28
|
+
// Optional: Waku options
|
|
29
|
+
pubSubTopic: '/waku/2/default-waku/proto',
|
|
30
|
+
feeExpirationTimeout: 30000, // 30 seconds
|
|
31
|
+
peerDiscoveryTimeout: 10000, // 10 seconds
|
|
32
|
+
additionalDirectPeers: [], // Optional: Direct peers to connect to
|
|
33
|
+
poiActiveListKeys: [], // Optional: POI keys
|
|
34
|
+
useDNSDiscovery: false, // Optional: Use DNS discovery
|
|
35
|
+
useCustomDNS: { // Optional: Custom DNS config
|
|
36
|
+
onlyCustom: false,
|
|
37
|
+
enrTreePeers: []
|
|
38
|
+
},
|
|
39
|
+
broadcasterVersionRange: { // Optional: Broadcaster version range
|
|
40
|
+
minVersion: '8.0.0',
|
|
41
|
+
maxVersion: '8.999.0'
|
|
42
|
+
}
|
|
43
|
+
};
|
|
12
44
|
|
|
13
|
-
|
|
14
|
-
|
|
45
|
+
const statusCallback = (status: BroadcasterConnectionStatus) => {
|
|
46
|
+
console.log('Connection status:', status);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
await WakuBroadcasterClient.start(chain, broadcasterOptions, statusCallback);
|
|
50
|
+
console.log('Waku Broadcaster Client started');
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Finding a Broadcaster
|
|
54
|
+
|
|
55
|
+
Once started, the client listens for fee updates from Broadcasters. You can query for the best broadcaster for a specific token.
|
|
15
56
|
|
|
16
|
-
|
|
17
|
-
|
|
57
|
+
```typescript
|
|
58
|
+
import { Chain } from '@railgun-community/shared-models';
|
|
18
59
|
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
60
|
+
const chain: Chain = { type: 0, id: 1 }; // Ethereum Mainnet
|
|
61
|
+
const tokenAddress = '0x6b175474e89094c44da98b954eedeac495271d0f'; // DAI
|
|
62
|
+
|
|
63
|
+
// Wait a few seconds for peer discovery and fee updates...
|
|
64
|
+
// In a UI, you might show a loading spinner or "Searching for broadcasters..." status.
|
|
65
|
+
|
|
66
|
+
const selectedBroadcaster = await WakuBroadcasterClient.findBestBroadcaster(
|
|
67
|
+
chain,
|
|
68
|
+
tokenAddress
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (selectedBroadcaster) {
|
|
72
|
+
console.log('Found broadcaster:', selectedBroadcaster.railgunAddress);
|
|
73
|
+
} else {
|
|
74
|
+
console.log('No broadcaster found for this token');
|
|
75
|
+
}
|
|
22
76
|
```
|
|
23
77
|
|
|
24
|
-
|
|
78
|
+
### 3. Sending a Transaction
|
|
79
|
+
|
|
80
|
+
Create a transaction and send it through the selected broadcaster.
|
|
25
81
|
|
|
26
|
-
|
|
82
|
+
```typescript
|
|
83
|
+
import { BroadcasterTransaction } from '@railgun-community/waku-broadcaster-client-web';
|
|
84
|
+
import { TXIDVersion } from '@railgun-community/shared-models';
|
|
85
|
+
|
|
86
|
+
// ... (Assume you have a railgunWallet and transactionRequest)
|
|
87
|
+
|
|
88
|
+
const txidVersion = TXIDVersion.V2_PoseidonMerkle; // or V3
|
|
89
|
+
const to = '0x...'; // Destination address
|
|
90
|
+
const data = '0x...'; // Transaction data
|
|
91
|
+
const nullifiers = ['0x...']; // Nullifiers
|
|
92
|
+
const overallBatchMinGasPrice = 1000000000n; // Min gas price
|
|
93
|
+
const useRelayAdapt = false; // Whether to use Relay Adapt
|
|
94
|
+
const preTransactionPOIs = {}; // POIs
|
|
95
|
+
|
|
96
|
+
const broadcasterTransaction = await BroadcasterTransaction.create(
|
|
97
|
+
txidVersion,
|
|
98
|
+
to,
|
|
99
|
+
data,
|
|
100
|
+
selectedBroadcaster.railgunAddress,
|
|
101
|
+
selectedBroadcaster.feesID,
|
|
102
|
+
chain,
|
|
103
|
+
nullifiers,
|
|
104
|
+
overallBatchMinGasPrice,
|
|
105
|
+
useRelayAdapt,
|
|
106
|
+
preTransactionPOIs
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const response = await BroadcasterTransaction.send(broadcasterTransaction);
|
|
111
|
+
console.log('Transaction submitted. Tx Hash:', response.txHash);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error('Failed to send transaction:', error);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
The `start` method accepts a `BroadcasterOptions` object.
|
|
120
|
+
|
|
121
|
+
- `trustedFeeSigner`: (Required) The public key of the trusted fee signer.
|
|
122
|
+
- `poiActiveListKeys`: (Optional) List of active POI list keys.
|
|
123
|
+
- `pubSubTopic`: (Optional) The Waku pubsub topic to subscribe to. Defaults to the RAILGUN topic.
|
|
124
|
+
- `additionalDirectPeers`: (Optional) Array of multiaddrs for direct peer connections.
|
|
125
|
+
- `peerDiscoveryTimeout`: (Optional) Timeout in milliseconds for peer discovery.
|
|
126
|
+
- `feeExpirationTimeout`: (Optional) Timeout in milliseconds for fee expiration.
|
|
127
|
+
- `useDNSDiscovery`: (Optional) Boolean to enable DNS peer discovery.
|
|
128
|
+
- `useCustomDNS`: (Optional) Configuration for custom DNS discovery.
|
|
129
|
+
- `onlyCustom`: (Boolean) If true, only use the provided `enrTreePeers`.
|
|
130
|
+
- `enrTreePeers`: (Array<string>) List of ENR tree URLs.
|
|
131
|
+
- `broadcasterVersionRange`: (Optional) Object specifying the allowed broadcaster version range.
|
|
132
|
+
- `minVersion`: (String) Minimum allowed version.
|
|
133
|
+
- `maxVersion`: (String) Maximum allowed version.
|
|
134
|
+
|
|
135
|
+
## Webpack Configuration
|
|
136
|
+
|
|
137
|
+
Some dependencies of this package, such as Waku and libp2p, make assumptions that they are running in a Node.js environment. This is not the case in a browser environment, so we need to configure Webpack to ignore some sub-dependencies that are not relevant in the browser.
|
|
27
138
|
|
|
28
139
|
**webpack.config.js**
|
|
29
140
|
|
|
@@ -31,33 +142,44 @@ Some dependencies of this package, such as Waku and libp2p, make an assumption t
|
|
|
31
142
|
module.exports = {
|
|
32
143
|
//...
|
|
33
144
|
resolve: {
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
145
|
+
fallback: {
|
|
146
|
+
// Polyfills for Node.js core modules if needed
|
|
147
|
+
"stream": require.resolve("stream-browserify"),
|
|
148
|
+
"crypto": require.resolve("crypto-browserify"),
|
|
149
|
+
}
|
|
39
150
|
},
|
|
40
151
|
};
|
|
41
152
|
```
|
|
42
153
|
|
|
43
|
-
|
|
154
|
+
### Next.js Configuration
|
|
155
|
+
|
|
156
|
+
If you are using **Next.js**, you need to handle server-side vs client-side bundling:
|
|
44
157
|
|
|
45
158
|
```js
|
|
46
159
|
/** @type {import('next').NextConfig} */
|
|
47
160
|
module.exports = {
|
|
48
161
|
webpack: (config, options) => {
|
|
49
162
|
if (options.isServer) {
|
|
50
|
-
// If your Next.js component is running in the server,
|
|
163
|
+
// If your Next.js component is running in the server, you need to avoid
|
|
51
164
|
// loading a WASM module.
|
|
52
165
|
config.resolve.alias['@railgun-community/curve25519-scalarmult-wasm'] =
|
|
53
166
|
'@railgun-community/curve25519-scalarmult-rsjs';
|
|
54
167
|
} else {
|
|
55
|
-
// If your Next.js component is running in the browser,
|
|
168
|
+
// If your Next.js component is running in the browser, you need to avoid
|
|
56
169
|
// loading some modules which call Node.js APIs such as `child_process`.
|
|
57
|
-
config.resolve.alias['default-gateway'] = false;
|
|
58
|
-
config.resolve.alias['@achingbrain/nat-port-mapper'] = false;
|
|
59
170
|
}
|
|
60
171
|
return config;
|
|
61
172
|
},
|
|
62
173
|
};
|
|
63
174
|
```
|
|
175
|
+
|
|
176
|
+
## Dependencies
|
|
177
|
+
|
|
178
|
+
This package relies on:
|
|
179
|
+
- `@waku/sdk`: For Waku networking.
|
|
180
|
+
- `@waku/discovery`: For peer discovery.
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT
|
|
185
|
+
|
|
@@ -13,6 +13,7 @@ export type BroadcasterFeeCacheState = {
|
|
|
13
13
|
};
|
|
14
14
|
export declare class BroadcasterFeeCache {
|
|
15
15
|
private static cache;
|
|
16
|
+
private static authorizedFees;
|
|
16
17
|
static lastSubscribedFeeMessageReceivedAt: Optional<number>;
|
|
17
18
|
private static poiActiveListKeys;
|
|
18
19
|
static init(poiActiveListKeys: string[]): void;
|
|
@@ -21,5 +22,7 @@ export declare class BroadcasterFeeCache {
|
|
|
21
22
|
static feesForChain(chain: Chain): Optional<BroadcasterFeeNetworkCacheMap>;
|
|
22
23
|
static feesForToken(chain: Chain, tokenAddress: string): Optional<BroadcasterFeeNetworkTokenCacheMap>;
|
|
23
24
|
static supportsToken(chain: Chain, tokenAddress: string, useRelayAdapt: boolean): boolean;
|
|
25
|
+
static addAuthorizedFees(tokenFeeMap: MapType<CachedTokenFee>): void;
|
|
26
|
+
static getAuthorizedFee(tokenAddress: string): Optional<CachedTokenFee>;
|
|
24
27
|
}
|
|
25
28
|
export {};
|
|
@@ -5,6 +5,7 @@ import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
|
|
|
5
5
|
import { nameForBroadcaster, cachedFeeExpired, DEFAULT_BROADCASTER_IDENTIFIER, invalidBroadcasterVersion, cachedFeeUnavailableOrExpired, } from '../utils/broadcaster-util.js';
|
|
6
6
|
export class BroadcasterFeeCache {
|
|
7
7
|
static cache = { forNetwork: {} };
|
|
8
|
+
static authorizedFees = {};
|
|
8
9
|
static lastSubscribedFeeMessageReceivedAt;
|
|
9
10
|
static poiActiveListKeys;
|
|
10
11
|
static init(poiActiveListKeys) {
|
|
@@ -80,5 +81,16 @@ export class BroadcasterFeeCache {
|
|
|
80
81
|
const availableUnexpiredFee = cachedFees.find(cachedFee => !cachedFeeUnavailableOrExpired(cachedFee, chain, useRelayAdapt));
|
|
81
82
|
return availableUnexpiredFee != null;
|
|
82
83
|
}
|
|
84
|
+
static addAuthorizedFees(tokenFeeMap) {
|
|
85
|
+
const newFees = Object.entries(tokenFeeMap);
|
|
86
|
+
const authorizedFees = {};
|
|
87
|
+
for (const [tokenAddress, feeMap] of newFees) {
|
|
88
|
+
authorizedFees[tokenAddress.toLowerCase()] = feeMap;
|
|
89
|
+
}
|
|
90
|
+
this.authorizedFees = authorizedFees;
|
|
91
|
+
}
|
|
92
|
+
static getAuthorizedFee(tokenAddress) {
|
|
93
|
+
return this.authorizedFees[tokenAddress.toLowerCase()];
|
|
94
|
+
}
|
|
83
95
|
}
|
|
84
96
|
//# sourceMappingURL=broadcaster-fee-cache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcaster-fee-cache.js","sourceRoot":"","sources":["../../src/fees/broadcaster-fee-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,eAAe,GAChB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,8BAA8B,EAC9B,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,8BAA8B,CAAC;AAgBtC,MAAM,OAAO,mBAAmB;IACtB,MAAM,CAAC,KAAK,GAA6B,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;
|
|
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_BROADCASTER_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 private static authorizedFees: MapType<CachedTokenFee> = {};\n static lastSubscribedFeeMessageReceivedAt: Optional<number>;\n private static poiActiveListKeys: Optional<string[]>;\n\n static init(poiActiveListKeys: string[]) {\n this.poiActiveListKeys = poiActiveListKeys;\n this.lastSubscribedFeeMessageReceivedAt = Date.now();\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_BROADCASTER_VERSION}-${BroadcasterConfig.MAXIMUM_BROADCASTER_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_BROADCASTER_IDENTIFIER] =\n tokenFeeMap[tokenAddress];\n });\n BroadcasterFeeCache.lastSubscribedFeeMessageReceivedAt = Date.now();\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 static addAuthorizedFees(tokenFeeMap: MapType<CachedTokenFee>) {\n const newFees = Object.entries(tokenFeeMap)\n const authorizedFees: MapType<CachedTokenFee> = {}\n for (const [tokenAddress, feeMap] of newFees) {\n authorizedFees[tokenAddress.toLowerCase()] = feeMap\n }\n this.authorizedFees = authorizedFees\n }\n\n static getAuthorizedFee(tokenAddress: string): Optional<CachedTokenFee> {\n return this.authorizedFees[tokenAddress.toLowerCase()];\n }\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
|
|
2
|
+
import { BroadcasterFeeCache } from './broadcaster-fee-cache.js';
|
|
3
|
+
import { cachedFeeExpired } from '../utils/broadcaster-util.js';
|
|
4
|
+
export const handleAuthorizedFees = (feeMessageData) => {
|
|
5
|
+
try {
|
|
6
|
+
if (cachedFeeExpired(feeMessageData.feeExpiration)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const tokenFeeMap = {};
|
|
10
|
+
const tokenAddresses = Object.keys(feeMessageData.fees);
|
|
11
|
+
tokenAddresses.forEach(tokenAddress => {
|
|
12
|
+
const feePerUnitGas = feeMessageData.fees[tokenAddress];
|
|
13
|
+
if (feePerUnitGas) {
|
|
14
|
+
const existingFee = BroadcasterFeeCache.getAuthorizedFee(tokenAddress.toLowerCase());
|
|
15
|
+
if (existingFee &&
|
|
16
|
+
existingFee.expiration >= feeMessageData.feeExpiration) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const cachedFee = {
|
|
20
|
+
feePerUnitGas,
|
|
21
|
+
expiration: feeMessageData.feeExpiration,
|
|
22
|
+
feesID: feeMessageData.feesID,
|
|
23
|
+
availableWallets: feeMessageData.availableWallets,
|
|
24
|
+
relayAdapt: feeMessageData.relayAdapt,
|
|
25
|
+
reliability: feeMessageData.reliability,
|
|
26
|
+
};
|
|
27
|
+
tokenFeeMap[tokenAddress] = cachedFee;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (Object.keys(tokenFeeMap).length > 0) {
|
|
31
|
+
BroadcasterFeeCache.addAuthorizedFees(tokenFeeMap);
|
|
32
|
+
BroadcasterDebug.log('Updated Authorized Fees');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
BroadcasterDebug.error(err);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=handle-authorized-fees-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-authorized-fees-message.js","sourceRoot":"","sources":["../../src/fees/handle-authorized-fees-message.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,cAAyC,EACzC,EAAE;IACF,IAAI,CAAC;QACH,IAAI,gBAAgB,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,CAAC;YACnD,OAAO;QACT,CAAC;QAED,MAAM,WAAW,GAA4B,EAAE,CAAC;QAChD,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACxD,cAAc,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;YACpC,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACxD,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,WAAW,GAAG,mBAAmB,CAAC,gBAAgB,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;gBACrF,IACE,WAAW;oBACX,WAAW,CAAC,UAAU,IAAI,cAAc,CAAC,aAAa,EACtD,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,MAAM,SAAS,GAAmB;oBAChC,aAAa;oBACb,UAAU,EAAE,cAAc,CAAC,aAAa;oBACxC,MAAM,EAAE,cAAc,CAAC,MAAM;oBAC7B,gBAAgB,EAAE,cAAc,CAAC,gBAAgB;oBACjD,UAAU,EAAE,cAAc,CAAC,UAAU;oBACrC,WAAW,EAAE,cAAc,CAAC,WAAW;iBACxC,CAAC;gBACF,WAAW,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC;YACxC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxC,mBAAmB,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACnD,gBAAgB,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,gBAAgB,CAAC,KAAK,CAAC,GAAY,CAAC,CAAC;IACvC,CAAC;AACH,CAAC,CAAC","sourcesContent":["import {\n BroadcasterFeeMessageData,\n CachedTokenFee,\n} from '@railgun-community/shared-models';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport { BroadcasterFeeCache } from './broadcaster-fee-cache.js';\nimport { cachedFeeExpired } from '../utils/broadcaster-util.js';\n\nexport const handleAuthorizedFees = (\n feeMessageData: BroadcasterFeeMessageData,\n) => {\n try {\n if (cachedFeeExpired(feeMessageData.feeExpiration)) {\n return;\n }\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 existingFee = BroadcasterFeeCache.getAuthorizedFee(tokenAddress.toLowerCase());\n if (\n existingFee &&\n existingFee.expiration >= feeMessageData.feeExpiration\n ) {\n return;\n }\n\n const cachedFee: CachedTokenFee = {\n feePerUnitGas,\n expiration: feeMessageData.feeExpiration,\n feesID: feeMessageData.feesID,\n availableWallets: feeMessageData.availableWallets,\n relayAdapt: feeMessageData.relayAdapt,\n reliability: feeMessageData.reliability,\n };\n tokenFeeMap[tokenAddress] = cachedFee;\n }\n });\n\n if (Object.keys(tokenFeeMap).length > 0) {\n BroadcasterFeeCache.addAuthorizedFees(tokenFeeMap);\n BroadcasterDebug.log('Updated Authorized Fees');\n }\n } catch (err) {\n BroadcasterDebug.error(err as Error);\n }\n};\n"]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Chain } from '@railgun-community/shared-models';
|
|
2
|
-
import { IMessage } from '@waku/
|
|
2
|
+
import { type IMessage } from '@waku/sdk';
|
|
3
3
|
export declare const handleBroadcasterFeesMessage: (chain: Chain, message: IMessage, contentTopic: string) => Promise<void>;
|
|
@@ -7,6 +7,7 @@ import { BroadcasterFeeCache } from './broadcaster-fee-cache.js';
|
|
|
7
7
|
import { invalidBroadcasterVersion } from '../utils/broadcaster-util.js';
|
|
8
8
|
import { bytesToUtf8, hexToUTF8String } from '../utils/conversion.js';
|
|
9
9
|
import { isDefined } from '../utils/is-defined.js';
|
|
10
|
+
import { handleAuthorizedFees } from './handle-authorized-fees-message.js';
|
|
10
11
|
const isExpiredTimestamp = (timestamp, expirationFeeTimestamp) => {
|
|
11
12
|
if (!timestamp || !expirationFeeTimestamp) {
|
|
12
13
|
return false;
|
|
@@ -17,6 +18,7 @@ const isExpiredTimestamp = (timestamp, expirationFeeTimestamp) => {
|
|
|
17
18
|
}
|
|
18
19
|
const nowTime = Date.now();
|
|
19
20
|
const expirationMsec = nowTime - 45 * 1000;
|
|
21
|
+
const expirationFeeMsec = nowTime + 45 * 1000;
|
|
20
22
|
const timestampExpired = messageTimestamp.getTime() < expirationMsec;
|
|
21
23
|
if (timestampExpired) {
|
|
22
24
|
BroadcasterDebug.log(`Broadcaster Fee STALE: Difference was ${(Date.now() - messageTimestamp.getTime()) / 1000}s`);
|
|
@@ -24,7 +26,8 @@ const isExpiredTimestamp = (timestamp, expirationFeeTimestamp) => {
|
|
|
24
26
|
else {
|
|
25
27
|
BroadcasterDebug.log(`Broadcaster Fee receipt SUCCESS in ${(Date.now() - messageTimestamp.getTime()) / 1000}s`);
|
|
26
28
|
}
|
|
27
|
-
|
|
29
|
+
const feeExpired = expirationFeeTimestamp.getTime() < expirationFeeMsec;
|
|
30
|
+
return timestampExpired && feeExpired;
|
|
28
31
|
};
|
|
29
32
|
export const handleBroadcasterFeesMessage = async (chain, message, contentTopic) => {
|
|
30
33
|
try {
|
|
@@ -66,15 +69,41 @@ export const handleBroadcasterFeesMessage = async (chain, message, contentTopic)
|
|
|
66
69
|
if (!(cause instanceof Error)) {
|
|
67
70
|
throw new Error('Unexpected non-error thrown', { cause });
|
|
68
71
|
}
|
|
69
|
-
BroadcasterDebug.error(new Error('Error handling Broadcaster fees', { cause }));
|
|
70
72
|
}
|
|
71
73
|
};
|
|
72
74
|
const updateFeesForBroadcaster = (chain, feeMessageData) => {
|
|
73
75
|
const tokenFeeMap = {};
|
|
74
76
|
const tokenAddresses = Object.keys(feeMessageData.fees);
|
|
77
|
+
const isTrustedSigner = BroadcasterConfig.trustedFeeSigner &&
|
|
78
|
+
feeMessageData.railgunAddress.toLowerCase() ===
|
|
79
|
+
BroadcasterConfig.trustedFeeSigner.toLowerCase();
|
|
80
|
+
if (isTrustedSigner) {
|
|
81
|
+
handleAuthorizedFees(feeMessageData);
|
|
82
|
+
}
|
|
75
83
|
tokenAddresses.forEach(tokenAddress => {
|
|
76
84
|
const feePerUnitGas = feeMessageData.fees[tokenAddress];
|
|
77
85
|
if (feePerUnitGas) {
|
|
86
|
+
if (!isTrustedSigner && BroadcasterConfig.trustedFeeSigner) {
|
|
87
|
+
const authorizedFee = BroadcasterFeeCache.getAuthorizedFee(tokenAddress.toLowerCase());
|
|
88
|
+
if (authorizedFee) {
|
|
89
|
+
const authorizedFeeAmount = BigInt(authorizedFee.feePerUnitGas);
|
|
90
|
+
const varianceLower = (authorizedFeeAmount *
|
|
91
|
+
BigInt(Math.round(BroadcasterConfig.authorizedFeeVariancePercentageLower * 100))) /
|
|
92
|
+
100n;
|
|
93
|
+
const varianceUpper = (authorizedFeeAmount *
|
|
94
|
+
BigInt(Math.round(BroadcasterConfig.authorizedFeeVariancePercentageUpper * 100))) /
|
|
95
|
+
100n;
|
|
96
|
+
const minFee = authorizedFeeAmount - varianceLower;
|
|
97
|
+
const maxFee = authorizedFeeAmount + varianceUpper;
|
|
98
|
+
const feeAmount = BigInt(feePerUnitGas);
|
|
99
|
+
if (feeAmount < minFee || feeAmount > maxFee) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
78
107
|
const cachedFee = {
|
|
79
108
|
feePerUnitGas,
|
|
80
109
|
expiration: feeMessageData.feeExpiration,
|
|
@@ -86,6 +115,8 @@ const updateFeesForBroadcaster = (chain, feeMessageData) => {
|
|
|
86
115
|
tokenFeeMap[tokenAddress] = cachedFee;
|
|
87
116
|
}
|
|
88
117
|
});
|
|
89
|
-
|
|
118
|
+
if (Object.keys(tokenFeeMap).length > 0) {
|
|
119
|
+
BroadcasterFeeCache.addTokenFees(chain, feeMessageData.railgunAddress, feeMessageData.feeExpiration, tokenFeeMap, feeMessageData.identifier, feeMessageData.version, feeMessageData.requiredPOIListKeys ?? []);
|
|
120
|
+
}
|
|
90
121
|
};
|
|
91
122
|
//# sourceMappingURL=handle-fees-message.js.map
|
|
@@ -1 +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 verifyBroadcasterSignature,\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 const verified = await verifyBroadcasterSignature(\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 reliability: feeMessageData.reliability,\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"]}
|
|
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 verifyBroadcasterSignature,\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 { type IMessage } from '@waku/sdk';\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';\nimport { handleAuthorizedFees } from './handle-authorized-fees-message.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. -- should be no longer an issue. \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 ${(Date.now() - messageTimestamp.getTime()) / 1000\n }s`,\n );\n } else {\n BroadcasterDebug.log(\n `Broadcaster Fee receipt SUCCESS in ${(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 const verified = await verifyBroadcasterSignature(\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};\n\nconst updateFeesForBroadcaster = (\n chain: Chain,\n feeMessageData: BroadcasterFeeMessageData,\n) => {\n const tokenFeeMap: MapType<CachedTokenFee> = {};\n const tokenAddresses = Object.keys(feeMessageData.fees);\n\n const isTrustedSigner =\n BroadcasterConfig.trustedFeeSigner &&\n feeMessageData.railgunAddress.toLowerCase() ===\n BroadcasterConfig.trustedFeeSigner.toLowerCase();\n\n if (isTrustedSigner) {\n handleAuthorizedFees(feeMessageData);\n }\n\n tokenAddresses.forEach(tokenAddress => {\n const feePerUnitGas = feeMessageData.fees[tokenAddress];\n if (feePerUnitGas) {\n if (!isTrustedSigner && BroadcasterConfig.trustedFeeSigner) {\n const authorizedFee = BroadcasterFeeCache.getAuthorizedFee(\n tokenAddress.toLowerCase(),\n );\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 const minFee = authorizedFeeAmount - varianceLower;\n const maxFee = authorizedFeeAmount + varianceUpper;\n\n const feeAmount = BigInt(feePerUnitGas);\n if (feeAmount < minFee || feeAmount > maxFee) {\n return;\n }\n } else {\n // No authorized fee, and we require one.\n return;\n }\n }\n\n const cachedFee: CachedTokenFee = {\n feePerUnitGas,\n expiration: feeMessageData.feeExpiration,\n feesID: feeMessageData.feesID,\n availableWallets: feeMessageData.availableWallets,\n relayAdapt: feeMessageData.relayAdapt,\n reliability: feeMessageData.reliability,\n };\n tokenFeeMap[tokenAddress] = cachedFee;\n }\n });\n\n if (Object.keys(tokenFeeMap).length > 0) {\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};\n"]}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
export type CustomDNSConfig = {
|
|
2
|
+
onlyCustom: boolean;
|
|
3
|
+
enrTreePeers: string[];
|
|
4
|
+
};
|
|
1
5
|
export declare class BroadcasterConfig {
|
|
2
6
|
static IS_DEV: boolean;
|
|
3
|
-
static
|
|
4
|
-
static
|
|
7
|
+
static trustedFeeSigner: string;
|
|
8
|
+
static feeExpirationTimeout: number;
|
|
9
|
+
static authorizedFeeVariancePercentageLower: number;
|
|
10
|
+
static authorizedFeeVariancePercentageUpper: number;
|
|
11
|
+
static MINIMUM_BROADCASTER_VERSION: string;
|
|
12
|
+
static MAXIMUM_BROADCASTER_VERSION: string;
|
|
13
|
+
static useDNSDiscovery: boolean;
|
|
14
|
+
static customDNS: CustomDNSConfig | undefined;
|
|
5
15
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export class BroadcasterConfig {
|
|
2
2
|
static IS_DEV = false;
|
|
3
|
+
static trustedFeeSigner;
|
|
4
|
+
static feeExpirationTimeout = 120_000;
|
|
5
|
+
static authorizedFeeVariancePercentageLower = 0.10;
|
|
6
|
+
static authorizedFeeVariancePercentageUpper = 0.30;
|
|
3
7
|
static MINIMUM_BROADCASTER_VERSION = '8.0.0';
|
|
4
8
|
static MAXIMUM_BROADCASTER_VERSION = '8.999.0';
|
|
9
|
+
static useDNSDiscovery = false;
|
|
10
|
+
static customDNS = undefined;
|
|
5
11
|
}
|
|
6
12
|
//# sourceMappingURL=broadcaster-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcaster-config.js","sourceRoot":"","sources":["../../src/models/broadcaster-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"broadcaster-config.js","sourceRoot":"","sources":["../../src/models/broadcaster-config.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,iBAAiB;IAC5B,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IAEtB,MAAM,CAAC,gBAAgB,CAAS;IAEhC,MAAM,CAAC,oBAAoB,GAAG,OAAO,CAAC;IAEtC,MAAM,CAAC,oCAAoC,GAAG,IAAI,CAAC;IACnD,MAAM,CAAC,oCAAoC,GAAG,IAAI,CAAC;IAEnD,MAAM,CAAC,2BAA2B,GAAG,OAAO,CAAC;IAC7C,MAAM,CAAC,2BAA2B,GAAG,SAAS,CAAC;IAE/C,MAAM,CAAC,eAAe,GAAG,KAAK,CAAA;IAC9B,MAAM,CAAC,SAAS,GAAgC,SAAS,CAAA","sourcesContent":["export type CustomDNSConfig = {\n onlyCustom: boolean,\n enrTreePeers: string[]\n}\nexport class BroadcasterConfig {\n static IS_DEV = false;\n\n static trustedFeeSigner: string;\n\n static feeExpirationTimeout = 120_000; // 2 minutes\n\n static authorizedFeeVariancePercentageLower = 0.10; // 10% lower variance\n static authorizedFeeVariancePercentageUpper = 0.30; // 30% upper variance\n\n static MINIMUM_BROADCASTER_VERSION = '8.0.0';\n static MAXIMUM_BROADCASTER_VERSION = '8.999.0';\n\n static useDNSDiscovery = false\n static customDNS: CustomDNSConfig | undefined = undefined\n}\n"]}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export declare const WAKU_RAILGUN_PUB_SUB_TOPIC = "/waku/2/rs/
|
|
1
|
+
export declare const WAKU_RAILGUN_PUB_SUB_TOPIC = "/waku/2/rs/1/1";
|
|
2
2
|
export declare const WAKU_RAILGUN_DEFAULT_SHARD: {
|
|
3
3
|
clusterId: number;
|
|
4
4
|
shard: number;
|
|
5
|
+
shardId: number;
|
|
6
|
+
pubsubTopic: string;
|
|
5
7
|
};
|
|
6
8
|
export declare const WAKU_RAILGUN_DEFAULT_SHARDS: {
|
|
7
9
|
clusterId: number;
|
package/dist/models/constants.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
export const WAKU_RAILGUN_PUB_SUB_TOPIC = '/waku/2/rs/
|
|
1
|
+
export const WAKU_RAILGUN_PUB_SUB_TOPIC = '/waku/2/rs/1/1';
|
|
2
2
|
export const WAKU_RAILGUN_DEFAULT_SHARD = {
|
|
3
|
-
clusterId:
|
|
3
|
+
clusterId: 1,
|
|
4
4
|
shard: 1,
|
|
5
|
+
shardId: 1,
|
|
6
|
+
pubsubTopic: WAKU_RAILGUN_PUB_SUB_TOPIC,
|
|
5
7
|
};
|
|
6
8
|
export const WAKU_RAILGUN_DEFAULT_SHARDS = {
|
|
7
|
-
clusterId:
|
|
9
|
+
clusterId: 1,
|
|
8
10
|
shards: [0, 1, 2, 3, 4, 5],
|
|
9
11
|
};
|
|
10
|
-
export const WAKU_RAILGUN_DEFAULT_PEERS_WEB = [
|
|
11
|
-
|
|
12
|
-
'/dns4/fleet.rootedinprivacy.com/tcp/8000/wss/p2p/16Uiu2HAm3GnUDQhBfax298CMkZX9MBHTJ9B8GXhrbueozESUaRZP',
|
|
13
|
-
];
|
|
14
|
-
export const WAKU_RAILGUN_DEFAULT_PEERS_NODE = [
|
|
15
|
-
'/dns4/core.rootedinprivacy.com/tcp/60000/p2p/16Uiu2HAm4Ai1GzKv4EykU26ST1BPT4AHtABsYCLKrDG74GWX7D6H',
|
|
16
|
-
'/dns4/fleet.rootedinprivacy.com/tcp/60000/p2p/16Uiu2HAm3GnUDQhBfax298CMkZX9MBHTJ9B8GXhrbueozESUaRZP',
|
|
17
|
-
];
|
|
12
|
+
export const WAKU_RAILGUN_DEFAULT_PEERS_WEB = [];
|
|
13
|
+
export const WAKU_RAILGUN_DEFAULT_PEERS_NODE = [];
|
|
18
14
|
//# sourceMappingURL=constants.js.map
|
|
@@ -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;
|
|
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,18 @@
|
|
|
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;
|
|
3
5
|
poiActiveListKeys?: string[];
|
|
4
6
|
pubSubTopic?: string;
|
|
5
7
|
additionalDirectPeers?: string[];
|
|
6
8
|
peerDiscoveryTimeout?: number;
|
|
9
|
+
feeExpirationTimeout?: number;
|
|
10
|
+
useDNSDiscovery?: boolean;
|
|
11
|
+
useCustomDNS?: CustomDNSConfig;
|
|
12
|
+
broadcasterVersionRange?: {
|
|
13
|
+
minVersion: string;
|
|
14
|
+
maxVersion: string;
|
|
15
|
+
};
|
|
7
16
|
};
|
|
8
17
|
export type BroadcasterConnectionStatusCallback = (chain: Chain, status: BroadcasterConnectionStatus) => void;
|
|
9
18
|
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;\n poiActiveListKeys?: string[];\n pubSubTopic?: string;\n additionalDirectPeers?: string[];\n peerDiscoveryTimeout?: number;\n feeExpirationTimeout?: 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
|
}
|