@railgun-community/waku-broadcaster-client-node 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/fees/broadcaster-fee-cache.d.ts +24 -0
- package/dist/fees/broadcaster-fee-cache.js +81 -0
- package/dist/fees/broadcaster-fee-cache.js.map +1 -0
- package/dist/fees/handle-fees-message.d.ts +3 -0
- package/dist/fees/handle-fees-message.js +90 -0
- package/dist/fees/handle-fees-message.js.map +1 -0
- package/dist/filters/address-filter.d.ts +7 -0
- package/dist/filters/address-filter.js +21 -0
- package/dist/filters/address-filter.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/models/broadcaster-config.d.ts +5 -0
- package/dist/models/broadcaster-config.js +6 -0
- package/dist/models/broadcaster-config.js.map +1 -0
- package/dist/models/constants.d.ts +3 -0
- package/dist/models/constants.js +10 -0
- package/dist/models/constants.js.map +1 -0
- package/dist/models/export-models.d.ts +12 -0
- package/dist/models/export-models.js +2 -0
- package/dist/models/export-models.js.map +1 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +2 -0
- package/dist/models/index.js.map +1 -0
- package/dist/search/best-broadcaster.d.ts +7 -0
- package/dist/search/best-broadcaster.js +95 -0
- package/dist/search/best-broadcaster.js.map +1 -0
- package/dist/status/broadcaster-connection-status.d.ts +6 -0
- package/dist/status/broadcaster-connection-status.js +72 -0
- package/dist/status/broadcaster-connection-status.js.map +1 -0
- package/dist/transact/broadcaster-transact-response.d.ts +13 -0
- package/dist/transact/broadcaster-transact-response.js +46 -0
- package/dist/transact/broadcaster-transact-response.js.map +1 -0
- package/dist/transact/broadcaster-transaction.d.ts +16 -0
- package/dist/transact/broadcaster-transaction.js +136 -0
- package/dist/transact/broadcaster-transaction.js.map +1 -0
- package/dist/transact/index.d.ts +1 -0
- package/dist/transact/index.js +2 -0
- package/dist/transact/index.js.map +1 -0
- package/dist/utils/broadcaster-debug.d.ts +7 -0
- package/dist/utils/broadcaster-debug.js +20 -0
- package/dist/utils/broadcaster-debug.js.map +1 -0
- package/dist/utils/broadcaster-util.d.ts +7 -0
- package/dist/utils/broadcaster-util.js +49 -0
- package/dist/utils/broadcaster-util.js.map +1 -0
- package/dist/utils/conversion.d.ts +4 -0
- package/dist/utils/conversion.js +14 -0
- package/dist/utils/conversion.js.map +1 -0
- package/dist/utils/is-defined.d.ts +1 -0
- package/dist/utils/is-defined.js +4 -0
- package/dist/utils/is-defined.js.map +1 -0
- package/dist/waku/waku-broadcaster-waku-core.d.ts +22 -0
- package/dist/waku/waku-broadcaster-waku-core.js +166 -0
- package/dist/waku/waku-broadcaster-waku-core.js.map +1 -0
- package/dist/waku/waku-observers.d.ts +16 -0
- package/dist/waku/waku-observers.js +101 -0
- package/dist/waku/waku-observers.js.map +1 -0
- package/dist/waku/waku-topics.d.ts +7 -0
- package/dist/waku/waku-topics.js +7 -0
- package/dist/waku/waku-topics.js.map +1 -0
- package/dist/waku-broadcaster-client.d.ts +32 -0
- package/dist/waku-broadcaster-client.js +147 -0
- package/dist/waku-broadcaster-client.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IMessage } from '@waku/interfaces';
|
|
2
|
+
export type WakuTransactResponse = {
|
|
3
|
+
id: string;
|
|
4
|
+
txHash?: string;
|
|
5
|
+
error?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare class BroadcasterTransactResponse {
|
|
8
|
+
static storedTransactionResponse: Optional<WakuTransactResponse>;
|
|
9
|
+
static sharedKey: Optional<Uint8Array>;
|
|
10
|
+
static setSharedKey: (key: Uint8Array) => void;
|
|
11
|
+
static clearSharedKey: () => void;
|
|
12
|
+
static handleBroadcasterTransactionResponseMessage(message: IMessage): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { decryptAESGCM256 } from '@railgun-community/wallet';
|
|
2
|
+
import { bytesToUtf8 } from '../utils/conversion.js';
|
|
3
|
+
import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
|
|
4
|
+
import { isDefined } from '../utils/is-defined.js';
|
|
5
|
+
export class BroadcasterTransactResponse {
|
|
6
|
+
static storedTransactionResponse;
|
|
7
|
+
static sharedKey;
|
|
8
|
+
static setSharedKey = (key) => {
|
|
9
|
+
BroadcasterTransactResponse.sharedKey = key;
|
|
10
|
+
BroadcasterTransactResponse.storedTransactionResponse = undefined;
|
|
11
|
+
};
|
|
12
|
+
static clearSharedKey = () => {
|
|
13
|
+
BroadcasterTransactResponse.sharedKey = undefined;
|
|
14
|
+
BroadcasterTransactResponse.storedTransactionResponse = undefined;
|
|
15
|
+
};
|
|
16
|
+
static async handleBroadcasterTransactionResponseMessage(message) {
|
|
17
|
+
BroadcasterDebug.log('Transact Response received.');
|
|
18
|
+
if (!BroadcasterTransactResponse.sharedKey) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!isDefined(message.payload)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const payload = bytesToUtf8(message.payload);
|
|
26
|
+
const { result: encryptedData } = JSON.parse(payload);
|
|
27
|
+
const decrypted = decryptAESGCM256(encryptedData, BroadcasterTransactResponse.sharedKey);
|
|
28
|
+
if (decrypted == null) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
BroadcasterDebug.log('Handle Broadcaster transact-response message:');
|
|
32
|
+
BroadcasterDebug.log(JSON.stringify(decrypted));
|
|
33
|
+
BroadcasterTransactResponse.storedTransactionResponse =
|
|
34
|
+
decrypted;
|
|
35
|
+
}
|
|
36
|
+
catch (cause) {
|
|
37
|
+
if (!(cause instanceof Error)) {
|
|
38
|
+
throw new Error('Unexpected non-error thrown', { cause });
|
|
39
|
+
}
|
|
40
|
+
BroadcasterDebug.error(new Error('Could not handle Broadcaster tx response message', {
|
|
41
|
+
cause,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=broadcaster-transact-response.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Chain, PreTransactionPOIsPerTxidLeafPerList, TXIDVersion } from '@railgun-community/shared-models';
|
|
2
|
+
export declare class BroadcasterTransaction {
|
|
3
|
+
private messageData;
|
|
4
|
+
private contentTopic;
|
|
5
|
+
private txidVersionForInputs;
|
|
6
|
+
private chain;
|
|
7
|
+
private nullifiers;
|
|
8
|
+
private constructor();
|
|
9
|
+
static create(txidVersionForInputs: TXIDVersion, to: string, data: string, broadcasterRailgunAddress: string, broadcasterFeesID: string, chain: Chain, nullifiers: string[], overallBatchMinGasPrice: bigint, useRelayAdapt: boolean, preTransactionPOIsPerTxidLeafPerList: PreTransactionPOIsPerTxidLeafPerList): Promise<BroadcasterTransaction>;
|
|
10
|
+
private static encryptTransaction;
|
|
11
|
+
private findMatchingNullifierTxid;
|
|
12
|
+
private getTransactionResponse;
|
|
13
|
+
private getRelayRetryState;
|
|
14
|
+
send(): Promise<string>;
|
|
15
|
+
private relay;
|
|
16
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { getRailgunWalletAddressData, encryptDataWithSharedKey, getCompletedTxidFromNullifiers, } from '@railgun-community/wallet';
|
|
2
|
+
import { poll, } from '@railgun-community/shared-models';
|
|
3
|
+
import { BroadcasterConfig } from '../models/broadcaster-config.js';
|
|
4
|
+
import { bytesToHex } from '../utils/conversion.js';
|
|
5
|
+
import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
|
|
6
|
+
import { isDefined } from '../utils/is-defined.js';
|
|
7
|
+
import { WakuBroadcasterWakuCore } from '../waku/waku-broadcaster-waku-core.js';
|
|
8
|
+
import { contentTopics } from '../waku/waku-topics.js';
|
|
9
|
+
import { BroadcasterTransactResponse, } from './broadcaster-transact-response.js';
|
|
10
|
+
import { getAddress, isHexString } from 'ethers';
|
|
11
|
+
var RelayRetryState;
|
|
12
|
+
(function (RelayRetryState) {
|
|
13
|
+
RelayRetryState["RetryTransact"] = "RetryTransact";
|
|
14
|
+
RelayRetryState["Wait"] = "Wait";
|
|
15
|
+
RelayRetryState["Timeout"] = "Timeout";
|
|
16
|
+
})(RelayRetryState || (RelayRetryState = {}));
|
|
17
|
+
const SECONDS_PER_RETRY = 12;
|
|
18
|
+
const POLL_DELAY_SECONDS = 0.2;
|
|
19
|
+
const RETRY_TRANSACTION_SECONDS = 45;
|
|
20
|
+
const POST_ALERT_TOTAL_WAITING_SECONDS = 220;
|
|
21
|
+
export class BroadcasterTransaction {
|
|
22
|
+
messageData;
|
|
23
|
+
contentTopic;
|
|
24
|
+
txidVersionForInputs;
|
|
25
|
+
chain;
|
|
26
|
+
nullifiers;
|
|
27
|
+
constructor(encryptedDataResponse, txidVersionForInputs, chain, nullifiers) {
|
|
28
|
+
this.messageData = {
|
|
29
|
+
method: 'transact',
|
|
30
|
+
params: {
|
|
31
|
+
pubkey: encryptedDataResponse.randomPubKey,
|
|
32
|
+
encryptedData: encryptedDataResponse.encryptedData,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
this.contentTopic = contentTopics.transact(chain);
|
|
36
|
+
this.txidVersionForInputs = txidVersionForInputs;
|
|
37
|
+
this.chain = chain;
|
|
38
|
+
this.nullifiers = nullifiers;
|
|
39
|
+
BroadcasterTransactResponse.setSharedKey(encryptedDataResponse.sharedKey);
|
|
40
|
+
}
|
|
41
|
+
static async create(txidVersionForInputs, to, data, broadcasterRailgunAddress, broadcasterFeesID, chain, nullifiers, overallBatchMinGasPrice, useRelayAdapt, preTransactionPOIsPerTxidLeafPerList) {
|
|
42
|
+
const encryptedDataResponse = await this.encryptTransaction(txidVersionForInputs, to, data, broadcasterRailgunAddress, broadcasterFeesID, chain, overallBatchMinGasPrice, useRelayAdapt, preTransactionPOIsPerTxidLeafPerList);
|
|
43
|
+
return new BroadcasterTransaction(encryptedDataResponse, txidVersionForInputs, chain, nullifiers);
|
|
44
|
+
}
|
|
45
|
+
static async encryptTransaction(txidVersionForInputs, to, data, broadcasterRailgunAddress, broadcasterFeesID, chain, overallBatchMinGasPrice, useRelayAdapt, preTransactionPOIsPerTxidLeafPerList) {
|
|
46
|
+
if (!isHexString(data)) {
|
|
47
|
+
throw new Error('Data field must be a hex string.');
|
|
48
|
+
}
|
|
49
|
+
const { viewingPublicKey: broadcasterViewingKey } = getRailgunWalletAddressData(broadcasterRailgunAddress);
|
|
50
|
+
const transactData = {
|
|
51
|
+
txidVersion: txidVersionForInputs,
|
|
52
|
+
to: getAddress(to),
|
|
53
|
+
data,
|
|
54
|
+
broadcasterViewingKey: bytesToHex(broadcasterViewingKey),
|
|
55
|
+
chainID: chain.id,
|
|
56
|
+
chainType: chain.type,
|
|
57
|
+
minGasPrice: overallBatchMinGasPrice.toString(),
|
|
58
|
+
feesID: broadcasterFeesID,
|
|
59
|
+
useRelayAdapt,
|
|
60
|
+
devLog: BroadcasterConfig.IS_DEV,
|
|
61
|
+
minVersion: BroadcasterConfig.MINIMUM_RELAYER_VERSION,
|
|
62
|
+
maxVersion: BroadcasterConfig.MAXIMUM_RELAYER_VERSION,
|
|
63
|
+
preTransactionPOIsPerTxidLeafPerList,
|
|
64
|
+
};
|
|
65
|
+
const encryptedDataResponse = await encryptDataWithSharedKey(transactData, broadcasterViewingKey);
|
|
66
|
+
return encryptedDataResponse;
|
|
67
|
+
}
|
|
68
|
+
async findMatchingNullifierTxid() {
|
|
69
|
+
try {
|
|
70
|
+
const { txid } = await getCompletedTxidFromNullifiers(this.txidVersionForInputs, this.chain, this.nullifiers);
|
|
71
|
+
return txid;
|
|
72
|
+
}
|
|
73
|
+
catch (cause) {
|
|
74
|
+
if (!(cause instanceof Error)) {
|
|
75
|
+
throw new Error('Unexpected non-error thrown', { cause });
|
|
76
|
+
}
|
|
77
|
+
BroadcasterDebug.error(new Error('Failed to find matching nullifier txid', { cause }));
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async getTransactionResponse() {
|
|
82
|
+
if (BroadcasterTransactResponse.storedTransactionResponse) {
|
|
83
|
+
return BroadcasterTransactResponse.storedTransactionResponse;
|
|
84
|
+
}
|
|
85
|
+
const nullifiersTxid = await this.findMatchingNullifierTxid();
|
|
86
|
+
if (isDefined(nullifiersTxid)) {
|
|
87
|
+
return {
|
|
88
|
+
id: 'nullifier-transaction',
|
|
89
|
+
txHash: nullifiersTxid,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
getRelayRetryState(retryNumber) {
|
|
95
|
+
const retrySeconds = retryNumber * SECONDS_PER_RETRY;
|
|
96
|
+
if (retrySeconds <= RETRY_TRANSACTION_SECONDS) {
|
|
97
|
+
return RelayRetryState.RetryTransact;
|
|
98
|
+
}
|
|
99
|
+
if (retrySeconds >= POST_ALERT_TOTAL_WAITING_SECONDS) {
|
|
100
|
+
return RelayRetryState.Timeout;
|
|
101
|
+
}
|
|
102
|
+
return RelayRetryState.Wait;
|
|
103
|
+
}
|
|
104
|
+
async send() {
|
|
105
|
+
return this.relay();
|
|
106
|
+
}
|
|
107
|
+
async relay(retryNumber = 0) {
|
|
108
|
+
const relayRetryState = this.getRelayRetryState(retryNumber);
|
|
109
|
+
switch (relayRetryState) {
|
|
110
|
+
case RelayRetryState.RetryTransact:
|
|
111
|
+
BroadcasterDebug.log(`Relay Waku message: ${this.messageData.method} via ${this.contentTopic}`);
|
|
112
|
+
await WakuBroadcasterWakuCore.relayMessage(this.messageData, this.contentTopic);
|
|
113
|
+
break;
|
|
114
|
+
case RelayRetryState.Wait:
|
|
115
|
+
break;
|
|
116
|
+
case RelayRetryState.Timeout:
|
|
117
|
+
throw new Error('Request timed out.');
|
|
118
|
+
}
|
|
119
|
+
const pollIterations = SECONDS_PER_RETRY / POLL_DELAY_SECONDS;
|
|
120
|
+
const response = await poll(async () => this.getTransactionResponse(), (result) => result != null, POLL_DELAY_SECONDS * 1000, pollIterations);
|
|
121
|
+
if (isDefined(response)) {
|
|
122
|
+
if (isDefined(response.txHash)) {
|
|
123
|
+
BroadcasterTransactResponse.clearSharedKey();
|
|
124
|
+
return response.txHash;
|
|
125
|
+
}
|
|
126
|
+
if (isDefined(response.error)) {
|
|
127
|
+
BroadcasterTransactResponse.clearSharedKey();
|
|
128
|
+
throw new Error('Failed to relay transaction on Waku', {
|
|
129
|
+
cause: new Error(response.error),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return this.relay(retryNumber + 1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=broadcaster-transaction.js.map
|
|
@@ -0,0 +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 RelayRetryState {\n RetryTransact = 'RetryTransact',\n Wait = 'Wait',\n Timeout = 'Timeout',\n}\n\ntype RelayMessageData = {\n method: string;\n params: BroadcasterEncryptedMethodParams;\n};\n\n// NOTE: Broadcaster default transaction-send timeout is 45 seconds.\nconst SECONDS_PER_RETRY = 12;\nconst POLL_DELAY_SECONDS = 0.2;\nconst RETRY_TRANSACTION_SECONDS = 45;\nconst POST_ALERT_TOTAL_WAITING_SECONDS = 220;\n\nexport class BroadcasterTransaction {\n private messageData: RelayMessageData;\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_RELAYER_VERSION,\n maxVersion: BroadcasterConfig.MAXIMUM_RELAYER_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 getRelayRetryState(retryNumber: number): RelayRetryState {\n const retrySeconds = retryNumber * SECONDS_PER_RETRY;\n if (retrySeconds <= RETRY_TRANSACTION_SECONDS) {\n return RelayRetryState.RetryTransact;\n }\n if (retrySeconds >= POST_ALERT_TOTAL_WAITING_SECONDS) {\n return RelayRetryState.Timeout;\n }\n return RelayRetryState.Wait;\n }\n\n async send(): Promise<string> {\n return this.relay();\n }\n\n private async relay(retryNumber = 0): Promise<string> {\n const relayRetryState = this.getRelayRetryState(retryNumber);\n switch (relayRetryState) {\n case RelayRetryState.RetryTransact:\n // 0-20 seconds.\n BroadcasterDebug.log(\n `Relay Waku message: ${this.messageData.method} via ${this.contentTopic}`,\n );\n await WakuBroadcasterWakuCore.relayMessage(\n this.messageData,\n this.contentTopic,\n );\n break;\n case RelayRetryState.Wait:\n // 21-60 seconds.\n // Do nothing.\n break;\n case RelayRetryState.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 BroadcasterTransactResponse.clearSharedKey();\n throw new Error('Failed to relay transaction on Waku', {\n cause: new Error(response.error),\n });\n }\n }\n\n // Retry.\n return this.relay(retryNumber + 1);\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './broadcaster-transaction.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transact/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC","sourcesContent":["export * from './broadcaster-transaction.js';\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BroadcasterDebugger } from '../models/export-models.js';
|
|
2
|
+
export declare class BroadcasterDebug {
|
|
3
|
+
private static debug;
|
|
4
|
+
static setDebugger(debug: BroadcasterDebugger): void;
|
|
5
|
+
static log(msg: string): void;
|
|
6
|
+
static error(err: Error, ignoreInTests?: boolean): void;
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class BroadcasterDebug {
|
|
2
|
+
static debug;
|
|
3
|
+
static setDebugger(debug) {
|
|
4
|
+
this.debug = debug;
|
|
5
|
+
}
|
|
6
|
+
static log(msg) {
|
|
7
|
+
if (this.debug) {
|
|
8
|
+
this.debug.log(msg);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
static error(err, ignoreInTests = false) {
|
|
12
|
+
if (this.debug) {
|
|
13
|
+
this.debug.error(err);
|
|
14
|
+
}
|
|
15
|
+
if (process.env.NODE_ENV === 'test' && !ignoreInTests) {
|
|
16
|
+
console.error(err);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=broadcaster-debug.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CachedTokenFee, Chain } from '@railgun-community/shared-models';
|
|
2
|
+
export declare const DEFAULT_RELAYER_IDENTIFIER = "default";
|
|
3
|
+
export declare const shortenAddress: (address: string) => string;
|
|
4
|
+
export declare const nameForBroadcaster: (railgunAddress: string, identifier: Optional<string>) => string;
|
|
5
|
+
export declare const cachedFeeExpired: (feeExpiration: number) => boolean;
|
|
6
|
+
export declare const invalidBroadcasterVersion: (version: Optional<string>) => boolean;
|
|
7
|
+
export declare const cachedFeeUnavailableOrExpired: (cachedFee: CachedTokenFee, chain: Chain, useRelayAdapt: boolean) => boolean;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { networkForChain, versionCompare, } from '@railgun-community/shared-models';
|
|
2
|
+
import { BroadcasterConfig } from '../models/broadcaster-config.js';
|
|
3
|
+
import { isDefined } from './is-defined.js';
|
|
4
|
+
const FEE_EXPIRATION_MINIMUM_MSEC = 40000;
|
|
5
|
+
export const DEFAULT_RELAYER_IDENTIFIER = 'default';
|
|
6
|
+
export const shortenAddress = (address) => {
|
|
7
|
+
if (address.length < 13) {
|
|
8
|
+
return address;
|
|
9
|
+
}
|
|
10
|
+
return `${address.slice(0, 8)}...${address.slice(-4)}`;
|
|
11
|
+
};
|
|
12
|
+
export const nameForBroadcaster = (railgunAddress, identifier) => {
|
|
13
|
+
const shortAddress = shortenAddress(railgunAddress);
|
|
14
|
+
if (isDefined(identifier)) {
|
|
15
|
+
return `${shortAddress}: ${identifier}`;
|
|
16
|
+
}
|
|
17
|
+
return shortAddress;
|
|
18
|
+
};
|
|
19
|
+
export const cachedFeeExpired = (feeExpiration) => {
|
|
20
|
+
return feeExpiration < Date.now() + FEE_EXPIRATION_MINIMUM_MSEC;
|
|
21
|
+
};
|
|
22
|
+
export const invalidBroadcasterVersion = (version) => {
|
|
23
|
+
return (versionCompare(version ?? '0.0.0', BroadcasterConfig.MINIMUM_RELAYER_VERSION) < 0 ||
|
|
24
|
+
versionCompare(version ?? '0.0.0', BroadcasterConfig.MAXIMUM_RELAYER_VERSION) > 0);
|
|
25
|
+
};
|
|
26
|
+
export const cachedFeeUnavailableOrExpired = (cachedFee, chain, useRelayAdapt) => {
|
|
27
|
+
if (useRelayAdapt) {
|
|
28
|
+
const relayAdapt = cachedFee.relayAdapt;
|
|
29
|
+
if (!relayAdapt) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
const network = networkForChain(chain);
|
|
33
|
+
if (!network) {
|
|
34
|
+
throw new Error(`Unrecognized chain ${chain}`);
|
|
35
|
+
}
|
|
36
|
+
const expectedRelayAdapt = network.relayAdaptContract;
|
|
37
|
+
if (relayAdapt && relayAdapt !== expectedRelayAdapt) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (cachedFee.availableWallets === 0) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
if (cachedFeeExpired(cachedFee.expiration)) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=broadcaster-util.js.map
|
|
@@ -0,0 +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,0BAA0B,GAAG,SAAS,CAAC;AAEpD,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,uBAAuB,CAC1C,GAAG,CAAC;QACL,cAAc,CACZ,OAAO,IAAI,OAAO,EAClB,iBAAiB,CAAC,uBAAuB,CAC1C,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;QACD,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;QACtD,IAAI,UAAU,IAAI,UAAU,KAAK,kBAAkB,EAAE;YACnD,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_RELAYER_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_RELAYER_VERSION,\n ) < 0 ||\n versionCompare(\n version ?? '0.0.0',\n BroadcasterConfig.MAXIMUM_RELAYER_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 const expectedRelayAdapt = network.relayAdaptContract;\n if (relayAdapt && relayAdapt !== expectedRelayAdapt) {\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"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const hexToUTF8String = (hexData) => {
|
|
2
|
+
const buffer = Buffer.from(hexData, 'hex');
|
|
3
|
+
return new TextDecoder().decode(buffer);
|
|
4
|
+
};
|
|
5
|
+
export const bytesToUtf8 = (bytes) => {
|
|
6
|
+
return Buffer.from(bytes).toString('utf8');
|
|
7
|
+
};
|
|
8
|
+
export const bytesToHex = (bytes) => {
|
|
9
|
+
return Buffer.from(bytes).toString('hex');
|
|
10
|
+
};
|
|
11
|
+
export const utf8ToBytes = (utf8) => {
|
|
12
|
+
return Buffer.from(utf8, 'utf8');
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=conversion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversion.js","sourceRoot":"","sources":["../../src/utils/conversion.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAe,EAAU,EAAE;IACzD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3C,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAiB,EAAU,EAAE;IACvD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAiB,EAAU,EAAE;IACtD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC5C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAc,EAAE;IACtD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC,CAAC","sourcesContent":["export const hexToUTF8String = (hexData: string): string => {\n const buffer = Buffer.from(hexData, 'hex');\n return new TextDecoder().decode(buffer);\n};\n\nexport const bytesToUtf8 = (bytes: Uint8Array): string => {\n return Buffer.from(bytes).toString('utf8');\n};\n\nexport const bytesToHex = (bytes: Uint8Array): string => {\n return Buffer.from(bytes).toString('hex');\n};\n\nexport const utf8ToBytes = (utf8: string): Uint8Array => {\n return Buffer.from(utf8, 'utf8');\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isDefined: <T>(a: T | null | undefined) => a is T;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-defined.js","sourceRoot":"","sources":["../../src/utils/is-defined.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,CAAI,CAAuB,EAAU,EAAE;IAC9D,OAAO,OAAO,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI,CAAC;AAChD,CAAC,CAAC","sourcesContent":["export const isDefined = <T>(a: T | undefined | null): a is T => {\n return typeof a !== 'undefined' && a !== null;\n};\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Chain } from '@railgun-community/shared-models';
|
|
2
|
+
import { RelayNode } from '@waku/interfaces';
|
|
3
|
+
import { BroadcasterOptions } from '../models/index.js';
|
|
4
|
+
export declare class WakuBroadcasterWakuCore {
|
|
5
|
+
static hasError: boolean;
|
|
6
|
+
static waku: Optional<RelayNode>;
|
|
7
|
+
private static MAX_RELAY_RETRIES;
|
|
8
|
+
private static pubSubTopic;
|
|
9
|
+
private static additionalDirectPeers;
|
|
10
|
+
private static peerDiscoveryTimeout;
|
|
11
|
+
static initWaku: (chain: Chain) => Promise<void>;
|
|
12
|
+
static reinitWaku: (chain: Chain) => Promise<void>;
|
|
13
|
+
static setBroadcasterOptions(BroadcasterOptions: BroadcasterOptions): void;
|
|
14
|
+
static disconnect: (removeObservers?: boolean) => Promise<void>;
|
|
15
|
+
private static connect;
|
|
16
|
+
static getMeshPeerCount(): number;
|
|
17
|
+
static getPubSubPeerCount(): number;
|
|
18
|
+
static getLightPushPeerCount(): Promise<number>;
|
|
19
|
+
static getFilterPeerCount(): Promise<number>;
|
|
20
|
+
private static waitForRemotePeer;
|
|
21
|
+
static relayMessage(data: object, contentTopic: string, retry?: number): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { delay, promiseTimeout } from '@railgun-community/shared-models';
|
|
2
|
+
import { waitForRemotePeer, createEncoder } from '@waku/core';
|
|
3
|
+
import { Protocols } from '@waku/interfaces';
|
|
4
|
+
import { WakuObservers } from './waku-observers.js';
|
|
5
|
+
import { BroadcasterDebug } from '../utils/broadcaster-debug.js';
|
|
6
|
+
import { BroadcasterFeeCache } from '../fees/broadcaster-fee-cache.js';
|
|
7
|
+
import { utf8ToBytes } from '../utils/conversion.js';
|
|
8
|
+
import { isDefined } from '../utils/is-defined.js';
|
|
9
|
+
import { bootstrap } from '@libp2p/bootstrap';
|
|
10
|
+
import { tcp } from '@libp2p/tcp';
|
|
11
|
+
import { createRelayNode } from '@waku/sdk/relay';
|
|
12
|
+
import { WAKU_RAILGUN_DEFAULT_PEERS_NODE, WAKU_RAILGUN_PUB_SUB_TOPIC, } from '../models/constants.js';
|
|
13
|
+
export class WakuBroadcasterWakuCore {
|
|
14
|
+
static hasError = false;
|
|
15
|
+
static waku;
|
|
16
|
+
static MAX_RELAY_RETRIES = 3;
|
|
17
|
+
static pubSubTopic = WAKU_RAILGUN_PUB_SUB_TOPIC;
|
|
18
|
+
static additionalDirectPeers = [];
|
|
19
|
+
static peerDiscoveryTimeout = 60000;
|
|
20
|
+
static initWaku = async (chain) => {
|
|
21
|
+
try {
|
|
22
|
+
await WakuBroadcasterWakuCore.connect();
|
|
23
|
+
if (!WakuBroadcasterWakuCore.waku) {
|
|
24
|
+
BroadcasterDebug.log('No waku instance found');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
WakuObservers.resetCurrentChain();
|
|
28
|
+
await WakuObservers.setObserversForChain(WakuBroadcasterWakuCore.waku, chain);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (!(err instanceof Error)) {
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
BroadcasterDebug.error(err);
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
static reinitWaku = async (chain) => {
|
|
39
|
+
if (isDefined(WakuBroadcasterWakuCore.waku) &&
|
|
40
|
+
WakuBroadcasterWakuCore.waku.isStarted()) {
|
|
41
|
+
await WakuBroadcasterWakuCore.disconnect();
|
|
42
|
+
}
|
|
43
|
+
BroadcasterFeeCache.resetCache(chain);
|
|
44
|
+
await WakuBroadcasterWakuCore.initWaku(chain);
|
|
45
|
+
};
|
|
46
|
+
static setBroadcasterOptions(BroadcasterOptions) {
|
|
47
|
+
if (isDefined(BroadcasterOptions.pubSubTopic)) {
|
|
48
|
+
WakuBroadcasterWakuCore.pubSubTopic = BroadcasterOptions.pubSubTopic;
|
|
49
|
+
}
|
|
50
|
+
if (BroadcasterOptions.additionalDirectPeers) {
|
|
51
|
+
WakuBroadcasterWakuCore.additionalDirectPeers =
|
|
52
|
+
BroadcasterOptions.additionalDirectPeers;
|
|
53
|
+
}
|
|
54
|
+
if (isDefined(BroadcasterOptions.peerDiscoveryTimeout)) {
|
|
55
|
+
WakuBroadcasterWakuCore.peerDiscoveryTimeout =
|
|
56
|
+
BroadcasterOptions.peerDiscoveryTimeout;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
static disconnect = async (removeObservers = false) => {
|
|
60
|
+
if (removeObservers) {
|
|
61
|
+
BroadcasterDebug.log('Disconnecting... Removing Observers.');
|
|
62
|
+
WakuObservers.removeAllObservers();
|
|
63
|
+
}
|
|
64
|
+
await WakuBroadcasterWakuCore.waku?.stop();
|
|
65
|
+
WakuBroadcasterWakuCore.waku = undefined;
|
|
66
|
+
};
|
|
67
|
+
static connect = async () => {
|
|
68
|
+
try {
|
|
69
|
+
WakuBroadcasterWakuCore.hasError = false;
|
|
70
|
+
BroadcasterDebug.log(`Creating waku relay client`);
|
|
71
|
+
const peers = [
|
|
72
|
+
...WAKU_RAILGUN_DEFAULT_PEERS_NODE,
|
|
73
|
+
...this.additionalDirectPeers,
|
|
74
|
+
];
|
|
75
|
+
const waitTimeoutBeforeBootstrap = 250;
|
|
76
|
+
const waku = await createRelayNode({
|
|
77
|
+
pubsubTopics: [WakuBroadcasterWakuCore.pubSubTopic],
|
|
78
|
+
pingKeepAlive: 60,
|
|
79
|
+
relayKeepAlive: 60,
|
|
80
|
+
libp2p: {
|
|
81
|
+
transports: [tcp()],
|
|
82
|
+
peerDiscovery: [
|
|
83
|
+
bootstrap({
|
|
84
|
+
list: peers,
|
|
85
|
+
timeout: waitTimeoutBeforeBootstrap,
|
|
86
|
+
}),
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
BroadcasterDebug.log('Start Waku.');
|
|
91
|
+
await waku.start();
|
|
92
|
+
BroadcasterDebug.log('Waiting for remote peer.');
|
|
93
|
+
await this.waitForRemotePeer(waku);
|
|
94
|
+
if (!isDefined(waku.relay)) {
|
|
95
|
+
throw new Error('No Waku Relay instantiated.');
|
|
96
|
+
}
|
|
97
|
+
BroadcasterDebug.log('Waku peers:');
|
|
98
|
+
for (const peer of waku.libp2p.getPeers()) {
|
|
99
|
+
BroadcasterDebug.log(JSON.stringify(peer));
|
|
100
|
+
}
|
|
101
|
+
BroadcasterDebug.log('Connected to Waku');
|
|
102
|
+
WakuBroadcasterWakuCore.waku = waku;
|
|
103
|
+
WakuBroadcasterWakuCore.hasError = false;
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
if (!(err instanceof Error)) {
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
WakuBroadcasterWakuCore.hasError = true;
|
|
110
|
+
throw err;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
static getMeshPeerCount() {
|
|
114
|
+
return (this.waku?.relay.getMeshPeers(WAKU_RAILGUN_PUB_SUB_TOPIC).length ?? 0);
|
|
115
|
+
}
|
|
116
|
+
static getPubSubPeerCount() {
|
|
117
|
+
const peers = this.waku?.libp2p.getPeers() ?? [];
|
|
118
|
+
return peers.length;
|
|
119
|
+
}
|
|
120
|
+
static async getLightPushPeerCount() {
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
static async getFilterPeerCount() {
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
static async waitForRemotePeer(waku) {
|
|
127
|
+
try {
|
|
128
|
+
const protocols = [Protocols.Relay];
|
|
129
|
+
await promiseTimeout(waitForRemotePeer(waku, protocols), WakuBroadcasterWakuCore.peerDiscoveryTimeout);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
if (!(err instanceof Error)) {
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
135
|
+
BroadcasterDebug.error(err);
|
|
136
|
+
throw new Error(err.message);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
static async relayMessage(data, contentTopic, retry = 0) {
|
|
140
|
+
if (!WakuBroadcasterWakuCore.waku?.relay) {
|
|
141
|
+
throw new Error('Relayer did not receive message. Please try again.');
|
|
142
|
+
}
|
|
143
|
+
const dataString = JSON.stringify(data);
|
|
144
|
+
const payload = utf8ToBytes(dataString);
|
|
145
|
+
const message = { payload };
|
|
146
|
+
try {
|
|
147
|
+
await WakuBroadcasterWakuCore.waku.relay.send(createEncoder({
|
|
148
|
+
contentTopic,
|
|
149
|
+
pubsubTopic: WakuBroadcasterWakuCore.pubSubTopic,
|
|
150
|
+
}), message);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
if (!(err instanceof Error)) {
|
|
154
|
+
throw err;
|
|
155
|
+
}
|
|
156
|
+
if (retry < WakuBroadcasterWakuCore.MAX_RELAY_RETRIES) {
|
|
157
|
+
await delay(1000);
|
|
158
|
+
return WakuBroadcasterWakuCore.relayMessage(data, contentTopic, retry + 1);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
BroadcasterDebug.error(err);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=waku-broadcaster-waku-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waku-broadcaster-waku-core.js","sourceRoot":"","sources":["../../src/waku/waku-broadcaster-waku-core.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chain, delay, promiseTimeout } from '@railgun-community/shared-models';\nimport { waitForRemotePeer, createEncoder } from '@waku/core';\nimport { Protocols, IMessage, RelayNode } from '@waku/interfaces';\nimport { WakuObservers } from './waku-observers.js';\nimport { BroadcasterDebug } from '../utils/broadcaster-debug.js';\nimport { BroadcasterFeeCache } from '../fees/broadcaster-fee-cache.js';\nimport { utf8ToBytes } from '../utils/conversion.js';\nimport { isDefined } from '../utils/is-defined.js';\nimport { bootstrap } from '@libp2p/bootstrap';\nimport { tcp } from '@libp2p/tcp';\nimport { createRelayNode } from '@waku/sdk/relay';\nimport { BroadcasterOptions } from '../models/index.js';\nimport {\n WAKU_RAILGUN_DEFAULT_PEERS_NODE,\n WAKU_RAILGUN_DEFAULT_PEERS_WEB,\n WAKU_RAILGUN_PUB_SUB_TOPIC,\n} from '../models/constants.js';\n\nexport class WakuBroadcasterWakuCore {\n static hasError = false;\n\n static waku: Optional<RelayNode>;\n private static MAX_RELAY_RETRIES = 3;\n private static pubSubTopic = WAKU_RAILGUN_PUB_SUB_TOPIC;\n private static additionalDirectPeers: string[] = [];\n private static peerDiscoveryTimeout = 60000;\n\n static initWaku = async (chain: Chain): Promise<void> => {\n try {\n await WakuBroadcasterWakuCore.connect();\n if (!WakuBroadcasterWakuCore.waku) {\n BroadcasterDebug.log('No waku instance found');\n return;\n }\n WakuObservers.resetCurrentChain();\n await WakuObservers.setObserversForChain(\n WakuBroadcasterWakuCore.waku,\n chain,\n );\n } catch (err) {\n if (!(err instanceof Error)) {\n throw err;\n }\n BroadcasterDebug.error(err);\n throw err;\n }\n };\n\n static reinitWaku = async (chain: Chain) => {\n if (\n isDefined(WakuBroadcasterWakuCore.waku) &&\n WakuBroadcasterWakuCore.waku.isStarted()\n ) {\n await WakuBroadcasterWakuCore.disconnect();\n }\n\n // Resets connection status to \"Connecting\" for this network.\n BroadcasterFeeCache.resetCache(chain);\n\n await WakuBroadcasterWakuCore.initWaku(chain);\n };\n\n static setBroadcasterOptions(BroadcasterOptions: BroadcasterOptions) {\n if (isDefined(BroadcasterOptions.pubSubTopic)) {\n WakuBroadcasterWakuCore.pubSubTopic = BroadcasterOptions.pubSubTopic;\n }\n if (BroadcasterOptions.additionalDirectPeers) {\n WakuBroadcasterWakuCore.additionalDirectPeers =\n BroadcasterOptions.additionalDirectPeers;\n }\n if (isDefined(BroadcasterOptions.peerDiscoveryTimeout)) {\n WakuBroadcasterWakuCore.peerDiscoveryTimeout =\n BroadcasterOptions.peerDiscoveryTimeout;\n }\n }\n\n static disconnect = async (removeObservers: boolean = false) => {\n if (removeObservers) {\n BroadcasterDebug.log('Disconnecting... Removing Observers.');\n WakuObservers.removeAllObservers();\n }\n await WakuBroadcasterWakuCore.waku?.stop();\n WakuBroadcasterWakuCore.waku = undefined;\n };\n\n private static connect = async (): Promise<void> => {\n try {\n WakuBroadcasterWakuCore.hasError = false;\n\n BroadcasterDebug.log(`Creating waku relay client`);\n\n const peers: string[] = [\n ...WAKU_RAILGUN_DEFAULT_PEERS_NODE,\n ...this.additionalDirectPeers,\n ];\n const waitTimeoutBeforeBootstrap = 250; // 250 ms - default is 1000ms\n const waku: RelayNode = await createRelayNode({\n pubsubTopics: [WakuBroadcasterWakuCore.pubSubTopic],\n pingKeepAlive: 60,\n relayKeepAlive: 60,\n libp2p: {\n transports: [tcp()],\n peerDiscovery: [\n bootstrap({\n list: peers,\n timeout: waitTimeoutBeforeBootstrap,\n }),\n ],\n },\n });\n\n BroadcasterDebug.log('Start Waku.');\n await waku.start();\n\n BroadcasterDebug.log('Waiting for remote peer.');\n await this.waitForRemotePeer(waku);\n\n if (!isDefined(waku.relay)) {\n throw new Error('No Waku Relay instantiated.');\n }\n\n BroadcasterDebug.log('Waku peers:');\n for (const peer of waku.libp2p.getPeers()) {\n BroadcasterDebug.log(JSON.stringify(peer));\n }\n\n BroadcasterDebug.log('Connected to Waku');\n WakuBroadcasterWakuCore.waku = waku;\n WakuBroadcasterWakuCore.hasError = false;\n } catch (err) {\n if (!(err instanceof Error)) {\n throw err;\n }\n WakuBroadcasterWakuCore.hasError = true;\n throw err;\n }\n };\n\n static getMeshPeerCount(): number {\n return (\n this.waku?.relay.getMeshPeers(WAKU_RAILGUN_PUB_SUB_TOPIC).length ?? 0\n );\n }\n\n static getPubSubPeerCount(): number {\n const peers = this.waku?.libp2p.getPeers() ?? [];\n return peers.length;\n }\n\n static async getLightPushPeerCount(): Promise<number> {\n return 0;\n }\n\n static async getFilterPeerCount(): Promise<number> {\n return 0;\n }\n\n private static async waitForRemotePeer(waku: RelayNode) {\n try {\n const protocols = [Protocols.Relay];\n await promiseTimeout(\n waitForRemotePeer(waku, protocols),\n WakuBroadcasterWakuCore.peerDiscoveryTimeout,\n );\n } catch (err) {\n if (!(err instanceof Error)) {\n throw err;\n }\n BroadcasterDebug.error(err);\n throw new Error(err.message);\n }\n }\n\n static async relayMessage(\n data: object,\n contentTopic: string,\n retry: number = 0,\n ): Promise<void> {\n if (!WakuBroadcasterWakuCore.waku?.relay) {\n throw new Error('Relayer did not receive message. Please try again.');\n }\n\n const dataString = JSON.stringify(data);\n const payload = utf8ToBytes(dataString);\n const message: IMessage = { payload };\n\n try {\n await WakuBroadcasterWakuCore.waku.relay.send(\n createEncoder({\n contentTopic,\n pubsubTopic: WakuBroadcasterWakuCore.pubSubTopic,\n }),\n message,\n );\n } catch (err) {\n if (!(err instanceof Error)) {\n throw err;\n }\n if (retry < WakuBroadcasterWakuCore.MAX_RELAY_RETRIES) {\n await delay(1000);\n return WakuBroadcasterWakuCore.relayMessage(\n data,\n contentTopic,\n retry + 1,\n );\n } else {\n BroadcasterDebug.error(err);\n }\n }\n }\n}\n"]}
|