@0xsequence/relayer 0.42.10 → 0.43.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/dist/0xsequence-relayer.cjs.dev.js +59 -151
- package/dist/0xsequence-relayer.cjs.prod.js +59 -151
- package/dist/0xsequence-relayer.esm.js +60 -148
- package/dist/declarations/src/base-relayer.d.ts +1 -1
- package/dist/declarations/src/local-relayer.d.ts +3 -4
- package/dist/declarations/src/provider-relayer.d.ts +3 -4
- package/dist/declarations/src/rpc-relayer/relayer.gen.d.ts +20 -1
- package/package.json +11 -10
- package/src/base-relayer.ts +4 -5
- package/src/local-relayer.ts +4 -5
- package/src/provider-relayer.ts +4 -5
- package/src/rpc-relayer/index.ts +1 -2
- package/src/rpc-relayer/relayer.gen.ts +190 -95
|
@@ -1,27 +1,21 @@
|
|
|
1
|
-
import { ethers, providers, Signer } from 'ethers';
|
|
1
|
+
import { ethers, providers, utils, Signer } from 'ethers';
|
|
2
2
|
import { walletContracts } from '@0xsequence/abi';
|
|
3
3
|
import { sequenceTxAbiEncode, readSequenceNonce, encodeNonce, computeMetaTxnHash, MetaTransactionsType, decodeNonce } from '@0xsequence/transactions';
|
|
4
4
|
import { isBigNumberish, logger } from '@0xsequence/utils';
|
|
5
|
-
import { Provider } from '@ethersproject/providers';
|
|
6
5
|
import { imageHash, addressOf, encodeSignature, buildStubSignature } from '@0xsequence/config';
|
|
7
|
-
import { Interface } from 'ethers/lib/utils';
|
|
8
|
-
import fetchPonyfill from 'fetch-ponyfill';
|
|
9
6
|
|
|
10
7
|
function _extends() {
|
|
11
|
-
_extends = Object.assign
|
|
8
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
12
9
|
for (var i = 1; i < arguments.length; i++) {
|
|
13
10
|
var source = arguments[i];
|
|
14
|
-
|
|
15
11
|
for (var key in source) {
|
|
16
12
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
17
13
|
target[key] = source[key];
|
|
18
14
|
}
|
|
19
15
|
}
|
|
20
16
|
}
|
|
21
|
-
|
|
22
17
|
return target;
|
|
23
18
|
};
|
|
24
|
-
|
|
25
19
|
return _extends.apply(this, arguments);
|
|
26
20
|
}
|
|
27
21
|
|
|
@@ -37,27 +31,22 @@ class BaseRelayer {
|
|
|
37
31
|
this.provider = void 0;
|
|
38
32
|
this.bundleCreation = void 0;
|
|
39
33
|
this.creationGasLimit = void 0;
|
|
40
|
-
|
|
41
34
|
const opts = _extends({}, BaseRelayerDefaults, options);
|
|
42
|
-
|
|
43
35
|
this.bundleCreation = opts.bundleCreation;
|
|
44
36
|
this.provider = opts.provider;
|
|
45
37
|
this.creationGasLimit = ethers.BigNumber.from(opts.creationGasLimit);
|
|
46
38
|
}
|
|
47
|
-
|
|
48
39
|
async isWalletDeployed(walletAddress) {
|
|
49
40
|
if (!this.provider) throw new Error('Bundled creation provider not found');
|
|
50
41
|
return (await this.provider.getCode(walletAddress)) !== '0x';
|
|
51
42
|
}
|
|
52
|
-
|
|
53
43
|
prepareWalletDeploy(config, context) {
|
|
54
|
-
const factoryInterface = new Interface(walletContracts.factory.abi);
|
|
44
|
+
const factoryInterface = new utils.Interface(walletContracts.factory.abi);
|
|
55
45
|
return {
|
|
56
46
|
to: context.factory,
|
|
57
47
|
data: factoryInterface.encodeFunctionData(factoryInterface.getFunction('deploy'), [context.mainModule, imageHash(config)])
|
|
58
48
|
};
|
|
59
49
|
}
|
|
60
|
-
|
|
61
50
|
async prependWalletDeploy(signedTransactions) {
|
|
62
51
|
const {
|
|
63
52
|
config,
|
|
@@ -67,14 +56,12 @@ class BaseRelayer {
|
|
|
67
56
|
signature
|
|
68
57
|
} = signedTransactions;
|
|
69
58
|
const walletAddress = addressOf(config, context);
|
|
70
|
-
const walletInterface = new Interface(walletContracts.mainModule.abi);
|
|
71
|
-
|
|
59
|
+
const walletInterface = new utils.Interface(walletContracts.mainModule.abi);
|
|
72
60
|
const encodedSignature = async function () {
|
|
73
61
|
const sig = await signature;
|
|
74
62
|
if (typeof sig === 'string') return sig;
|
|
75
63
|
return encodeSignature(sig);
|
|
76
64
|
}();
|
|
77
|
-
|
|
78
65
|
if (this.bundleCreation && !(await this.isWalletDeployed(walletAddress))) {
|
|
79
66
|
return {
|
|
80
67
|
to: context.guestModule,
|
|
@@ -107,15 +94,12 @@ class BaseRelayer {
|
|
|
107
94
|
};
|
|
108
95
|
}
|
|
109
96
|
}
|
|
110
|
-
|
|
111
97
|
async prepareTransactions(config, context, signature, ...transactions) {
|
|
112
98
|
//, gasLimit?: ethers.BigNumberish }> {
|
|
113
99
|
const nonce = readSequenceNonce(...transactions);
|
|
114
|
-
|
|
115
100
|
if (!nonce) {
|
|
116
101
|
throw new Error('Unable to prepare transactions without a defined nonce');
|
|
117
102
|
}
|
|
118
|
-
|
|
119
103
|
const {
|
|
120
104
|
to,
|
|
121
105
|
execute
|
|
@@ -126,13 +110,12 @@ class BaseRelayer {
|
|
|
126
110
|
nonce,
|
|
127
111
|
signature
|
|
128
112
|
});
|
|
129
|
-
const walletInterface = new Interface(walletContracts.mainModule.abi);
|
|
113
|
+
const walletInterface = new utils.Interface(walletContracts.mainModule.abi);
|
|
130
114
|
return {
|
|
131
115
|
to,
|
|
132
116
|
data: walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature])
|
|
133
117
|
};
|
|
134
118
|
}
|
|
135
|
-
|
|
136
119
|
}
|
|
137
120
|
|
|
138
121
|
const DEFAULT_GAS_LIMIT = ethers.BigNumber.from(800000);
|
|
@@ -142,7 +125,7 @@ const ProviderRelayerDefaults = {
|
|
|
142
125
|
fromBlockLog: -1024
|
|
143
126
|
};
|
|
144
127
|
function isProviderRelayerOptions(obj) {
|
|
145
|
-
return obj.provider !== undefined && Provider.isProvider(obj.provider);
|
|
128
|
+
return obj.provider !== undefined && providers.Provider.isProvider(obj.provider);
|
|
146
129
|
}
|
|
147
130
|
class ProviderRelayer extends BaseRelayer {
|
|
148
131
|
constructor(options) {
|
|
@@ -151,40 +134,35 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
151
134
|
this.waitPollRate = void 0;
|
|
152
135
|
this.deltaBlocksLog = void 0;
|
|
153
136
|
this.fromBlockLog = void 0;
|
|
154
|
-
|
|
155
137
|
const opts = _extends({}, ProviderRelayerDefaults, options);
|
|
156
|
-
|
|
157
138
|
this.provider = opts.provider;
|
|
158
139
|
this.waitPollRate = opts.waitPollRate;
|
|
159
140
|
this.deltaBlocksLog = opts.deltaBlocksLog;
|
|
160
141
|
this.fromBlockLog = opts.fromBlockLog;
|
|
161
142
|
}
|
|
162
|
-
|
|
163
143
|
async simulate(wallet, ...transactions) {
|
|
164
144
|
var _this = this;
|
|
165
|
-
|
|
166
145
|
return (await Promise.all(transactions.map(async function (tx) {
|
|
167
146
|
// Respect gasLimit request of the transaction (as long as its not 0)
|
|
168
147
|
if (tx.gasLimit && !ethers.BigNumber.from(tx.gasLimit || 0).eq(ethers.constants.Zero)) {
|
|
169
148
|
return tx.gasLimit;
|
|
170
|
-
}
|
|
171
|
-
|
|
149
|
+
}
|
|
172
150
|
|
|
151
|
+
// Fee can't be estimated locally for delegateCalls
|
|
173
152
|
if (tx.delegateCall) {
|
|
174
153
|
return DEFAULT_GAS_LIMIT;
|
|
175
|
-
}
|
|
176
|
-
|
|
154
|
+
}
|
|
177
155
|
|
|
156
|
+
// Fee can't be estimated for self-called if wallet hasn't been deployed
|
|
178
157
|
if (tx.to === wallet && !(await _this.isWalletDeployed(wallet))) {
|
|
179
158
|
return DEFAULT_GAS_LIMIT;
|
|
180
159
|
}
|
|
181
|
-
|
|
182
160
|
if (!_this.provider) {
|
|
183
161
|
throw new Error('signer.provider is not set, but is required');
|
|
184
|
-
}
|
|
185
|
-
// estimated with more accurately by using self-calls with the batch transactions one by one
|
|
186
|
-
|
|
162
|
+
}
|
|
187
163
|
|
|
164
|
+
// TODO: If the wallet address has been deployed, gas limits can be
|
|
165
|
+
// estimated with more accurately by using self-calls with the batch transactions one by one
|
|
188
166
|
return _this.provider.estimateGas({
|
|
189
167
|
from: wallet,
|
|
190
168
|
to: tx.to,
|
|
@@ -198,48 +176,37 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
198
176
|
gasLimit: ethers.BigNumber.from(gasLimit).toNumber()
|
|
199
177
|
}));
|
|
200
178
|
}
|
|
201
|
-
|
|
202
179
|
async getNonce(config, context, space, blockTag) {
|
|
203
180
|
if (!this.provider) {
|
|
204
181
|
throw new Error('provider is not set');
|
|
205
182
|
}
|
|
206
|
-
|
|
207
183
|
const addr = addressOf(config, context);
|
|
208
|
-
|
|
209
184
|
if ((await this.provider.getCode(addr)) === '0x') {
|
|
210
185
|
return 0;
|
|
211
186
|
}
|
|
212
|
-
|
|
213
187
|
if (space === undefined) {
|
|
214
188
|
space = 0;
|
|
215
189
|
}
|
|
216
|
-
|
|
217
190
|
const module = new ethers.Contract(addr, walletContracts.mainModule.abi, this.provider);
|
|
218
191
|
const nonce = await module.readNonce(space, {
|
|
219
192
|
blockTag: blockTag
|
|
220
193
|
});
|
|
221
194
|
return encodeNonce(space, nonce);
|
|
222
195
|
}
|
|
223
|
-
|
|
224
196
|
async wait(metaTxnId, timeout, delay = this.waitPollRate, maxFails = 5) {
|
|
225
197
|
var _this2 = this;
|
|
226
|
-
|
|
227
198
|
if (typeof metaTxnId !== 'string') {
|
|
228
199
|
logger.info('computing id', metaTxnId.config, metaTxnId.context, metaTxnId.chainId, ...metaTxnId.transactions);
|
|
229
200
|
metaTxnId = computeMetaTxnHash(addressOf(metaTxnId.config, metaTxnId.context), metaTxnId.chainId, ...metaTxnId.transactions);
|
|
230
201
|
}
|
|
231
|
-
|
|
232
202
|
let timedOut = false;
|
|
233
|
-
|
|
234
203
|
const retry = async function retry(f, errorMessage) {
|
|
235
204
|
let fails = 0;
|
|
236
|
-
|
|
237
205
|
while (!timedOut) {
|
|
238
206
|
try {
|
|
239
207
|
return await f();
|
|
240
208
|
} catch (error) {
|
|
241
209
|
fails++;
|
|
242
|
-
|
|
243
210
|
if (maxFails !== undefined && fails >= maxFails) {
|
|
244
211
|
logger.error(`giving up after ${fails} failed attempts${errorMessage ? `: ${errorMessage}` : ''}`, error);
|
|
245
212
|
throw error;
|
|
@@ -247,31 +214,24 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
247
214
|
logger.warn(`attempt #${fails} failed${errorMessage ? `: ${errorMessage}` : ''}`, error);
|
|
248
215
|
}
|
|
249
216
|
}
|
|
250
|
-
|
|
251
217
|
if (delay > 0) {
|
|
252
218
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
253
219
|
}
|
|
254
220
|
}
|
|
255
|
-
|
|
256
221
|
throw new Error(`timed out after ${fails} failed attempts${errorMessage ? `: ${errorMessage}` : ''}`);
|
|
257
222
|
};
|
|
258
|
-
|
|
259
223
|
const waitReceipt = async function waitReceipt() {
|
|
260
224
|
// Transactions can only get executed on nonce change
|
|
261
225
|
// get all nonce changes and look for metaTxnIds in between logs
|
|
262
226
|
let lastBlock = _this2.fromBlockLog;
|
|
263
|
-
|
|
264
227
|
if (lastBlock < 0) {
|
|
265
228
|
const block = await retry(() => _this2.provider.getBlockNumber(), 'unable to get latest block number');
|
|
266
229
|
lastBlock = block + lastBlock;
|
|
267
230
|
}
|
|
268
|
-
|
|
269
231
|
if (typeof metaTxnId !== 'string') {
|
|
270
232
|
throw new Error('impossible');
|
|
271
233
|
}
|
|
272
|
-
|
|
273
234
|
const normalMetaTxnId = metaTxnId.replace('0x', '');
|
|
274
|
-
|
|
275
235
|
while (!timedOut) {
|
|
276
236
|
const block = await retry(() => _this2.provider.getBlockNumber(), 'unable to get latest block number');
|
|
277
237
|
const logs = await retry(() => _this2.provider.getLogs({
|
|
@@ -280,28 +240,30 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
280
240
|
// Nonce change event topic
|
|
281
241
|
topics: ['0x1f180c27086c7a39ea2a7b25239d1ab92348f07ca7bb59d1438fcf527568f881']
|
|
282
242
|
}), `unable to get NonceChange logs for blocks ${Math.max(0, lastBlock - _this2.deltaBlocksLog)} to ${block}`);
|
|
283
|
-
lastBlock = block;
|
|
243
|
+
lastBlock = block;
|
|
284
244
|
|
|
285
|
-
|
|
245
|
+
// Get receipts of all transactions
|
|
246
|
+
const txs = await Promise.all(logs.map(l => retry(() => _this2.provider.getTransactionReceipt(l.transactionHash), `unable to get receipt for transaction ${l.transactionHash}`)));
|
|
286
247
|
|
|
287
|
-
|
|
288
|
-
|
|
248
|
+
// Find a transaction with a TxExecuted log
|
|
249
|
+
const found = txs.find(tx => tx.logs.find(l => l.topics.length === 0 && l.data.replace('0x', '') === normalMetaTxnId || l.topics.length === 1 &&
|
|
250
|
+
// TxFailed event topic
|
|
251
|
+
l.topics[0] === '0x3dbd1590ea96dd3253a91f24e64e3a502e1225d602a5731357bc12643070ccd7' && l.data.length >= 64 && l.data.replace('0x', '').startsWith(normalMetaTxnId)));
|
|
289
252
|
|
|
253
|
+
// If found return that
|
|
290
254
|
if (found) {
|
|
291
255
|
return _extends({
|
|
292
256
|
receipt: found
|
|
293
257
|
}, await retry(() => _this2.provider.getTransaction(found.transactionHash), `unable to get transaction ${found.transactionHash}`));
|
|
294
|
-
}
|
|
295
|
-
|
|
258
|
+
}
|
|
296
259
|
|
|
260
|
+
// Otherwise wait and try again
|
|
297
261
|
if (!timedOut) {
|
|
298
262
|
await new Promise(r => setTimeout(r, delay));
|
|
299
263
|
}
|
|
300
264
|
}
|
|
301
|
-
|
|
302
265
|
throw new Error(`Timeout waiting for transaction receipt ${metaTxnId}`);
|
|
303
266
|
};
|
|
304
|
-
|
|
305
267
|
if (timeout !== undefined) {
|
|
306
268
|
return Promise.race([waitReceipt(), new Promise((_, reject) => setTimeout(() => {
|
|
307
269
|
timedOut = true;
|
|
@@ -311,7 +273,6 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
311
273
|
return waitReceipt();
|
|
312
274
|
}
|
|
313
275
|
}
|
|
314
|
-
|
|
315
276
|
}
|
|
316
277
|
|
|
317
278
|
function isLocalRelayerOptions(obj) {
|
|
@@ -329,50 +290,46 @@ class LocalRelayer extends ProviderRelayer {
|
|
|
329
290
|
this.signer = Signer.isSigner(options) ? options : options.signer;
|
|
330
291
|
if (!this.signer.provider) throw new Error("Signer must have a provider");
|
|
331
292
|
}
|
|
332
|
-
|
|
333
293
|
async deployWallet(config, context) {
|
|
334
294
|
// NOTE: on hardhat some tests fail on HookCallerMock when not passing gasLimit directly as below,
|
|
335
295
|
// and using eth_gasEstimate. Perhaps review HookCallerMock.sol and fix it to avoid what looks
|
|
336
296
|
// like an infinite loop?
|
|
337
|
-
const walletDeployTxn = this.prepareWalletDeploy(config, context);
|
|
297
|
+
const walletDeployTxn = this.prepareWalletDeploy(config, context);
|
|
338
298
|
|
|
299
|
+
// NOTE: for hardhat to pass, we have to set the gasLimit directly, as its unable to estimate
|
|
339
300
|
return this.signer.sendTransaction(_extends({}, walletDeployTxn, {
|
|
340
301
|
gasLimit: ethers.constants.Two.pow(17)
|
|
341
302
|
}));
|
|
342
303
|
}
|
|
343
|
-
|
|
344
304
|
async getFeeOptions(_config, _context, ..._transactions) {
|
|
345
305
|
return {
|
|
346
306
|
options: []
|
|
347
307
|
};
|
|
348
308
|
}
|
|
349
|
-
|
|
350
309
|
async gasRefundOptions(config, context, ...transactions) {
|
|
351
310
|
const {
|
|
352
311
|
options
|
|
353
312
|
} = await this.getFeeOptions(config, context, ...transactions);
|
|
354
313
|
return options;
|
|
355
314
|
}
|
|
356
|
-
|
|
357
315
|
setTransactionOptions(transactionRequest) {
|
|
358
316
|
this.txnOptions = transactionRequest;
|
|
359
317
|
}
|
|
360
|
-
|
|
361
318
|
async relay(signedTxs, quote, waitForReceipt = true) {
|
|
362
319
|
if (quote !== undefined) {
|
|
363
320
|
logger.warn(`LocalRelayer doesn't accept fee quotes`);
|
|
364
321
|
}
|
|
365
|
-
|
|
366
322
|
if (!signedTxs.context.guestModule || signedTxs.context.guestModule.length !== 42) {
|
|
367
323
|
throw new Error('LocalRelayer requires the context.guestModule address');
|
|
368
324
|
}
|
|
369
|
-
|
|
370
325
|
const {
|
|
371
326
|
to,
|
|
372
327
|
execute
|
|
373
328
|
} = await this.prependWalletDeploy(signedTxs);
|
|
374
329
|
const walletInterface = new ethers.utils.Interface(walletContracts.mainModule.abi);
|
|
375
|
-
const data = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
330
|
+
const data = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
331
|
+
|
|
332
|
+
// TODO: think about computing gas limit individually, summing together and passing across
|
|
376
333
|
// NOTE: we expect that all txns have set their gasLimit ahead of time through proper estimation
|
|
377
334
|
// const gasLimit = signedTxs.transactions.reduce((sum, tx) => sum.add(tx.gasLimit), ethers.BigNumber.from(0))
|
|
378
335
|
// txRequest.gasLimit = gasLimit
|
|
@@ -381,7 +338,6 @@ class LocalRelayer extends ProviderRelayer {
|
|
|
381
338
|
to,
|
|
382
339
|
data
|
|
383
340
|
}, this.txnOptions));
|
|
384
|
-
|
|
385
341
|
if (waitForReceipt) {
|
|
386
342
|
const response = await responsePromise;
|
|
387
343
|
response.receipt = await response.wait();
|
|
@@ -390,25 +346,28 @@ class LocalRelayer extends ProviderRelayer {
|
|
|
390
346
|
return responsePromise;
|
|
391
347
|
}
|
|
392
348
|
}
|
|
393
|
-
|
|
394
349
|
}
|
|
395
350
|
|
|
396
351
|
/* eslint-disable */
|
|
397
|
-
// sequence-relayer v0.4.0
|
|
352
|
+
// sequence-relayer v0.4.0 dd44f90f38fc726a1f1430cfece544c3316f6b4f
|
|
398
353
|
// --
|
|
399
|
-
//
|
|
400
|
-
//
|
|
354
|
+
// Code generated by webrpc-gen@v0.7.0 with typescript generator. DO NOT EDIT.
|
|
355
|
+
//
|
|
356
|
+
// webrpc-gen -schema=relayer.ridl -target=typescript -client -out=./clients/relayer.gen.ts
|
|
357
|
+
|
|
401
358
|
// WebRPC description and code-gen version
|
|
402
|
-
const WebRPCVersion =
|
|
359
|
+
const WebRPCVersion = "v1";
|
|
360
|
+
|
|
361
|
+
// Schema version of your RIDL schema
|
|
362
|
+
const WebRPCSchemaVersion = "v0.4.0";
|
|
403
363
|
|
|
404
|
-
|
|
364
|
+
// Schema hash generated from your RIDL schema
|
|
365
|
+
const WebRPCSchemaHash = "dd44f90f38fc726a1f1430cfece544c3316f6b4f";
|
|
405
366
|
|
|
406
|
-
|
|
367
|
+
//
|
|
407
368
|
// Types
|
|
408
369
|
//
|
|
409
|
-
|
|
410
370
|
let ETHTxnStatus;
|
|
411
|
-
|
|
412
371
|
(function (ETHTxnStatus) {
|
|
413
372
|
ETHTxnStatus["UNKNOWN"] = "UNKNOWN";
|
|
414
373
|
ETHTxnStatus["DROPPED"] = "DROPPED";
|
|
@@ -418,9 +377,7 @@ let ETHTxnStatus;
|
|
|
418
377
|
ETHTxnStatus["PARTIALLY_FAILED"] = "PARTIALLY_FAILED";
|
|
419
378
|
ETHTxnStatus["FAILED"] = "FAILED";
|
|
420
379
|
})(ETHTxnStatus || (ETHTxnStatus = {}));
|
|
421
|
-
|
|
422
380
|
let TransferType;
|
|
423
|
-
|
|
424
381
|
(function (TransferType) {
|
|
425
382
|
TransferType["SEND"] = "SEND";
|
|
426
383
|
TransferType["RECEIVE"] = "RECEIVE";
|
|
@@ -429,22 +386,17 @@ let TransferType;
|
|
|
429
386
|
TransferType["BURN"] = "BURN";
|
|
430
387
|
TransferType["UNKNOWN"] = "UNKNOWN";
|
|
431
388
|
})(TransferType || (TransferType = {}));
|
|
432
|
-
|
|
433
389
|
let FeeTokenType;
|
|
434
|
-
|
|
435
390
|
(function (FeeTokenType) {
|
|
436
391
|
FeeTokenType["UNKNOWN"] = "UNKNOWN";
|
|
437
392
|
FeeTokenType["ERC20_TOKEN"] = "ERC20_TOKEN";
|
|
438
393
|
FeeTokenType["ERC1155_TOKEN"] = "ERC1155_TOKEN";
|
|
439
394
|
})(FeeTokenType || (FeeTokenType = {}));
|
|
440
|
-
|
|
441
395
|
let SortOrder;
|
|
442
|
-
|
|
443
396
|
(function (SortOrder) {
|
|
444
397
|
SortOrder["DESC"] = "DESC";
|
|
445
398
|
SortOrder["ASC"] = "ASC";
|
|
446
399
|
})(SortOrder || (SortOrder = {}));
|
|
447
|
-
|
|
448
400
|
//
|
|
449
401
|
// Client
|
|
450
402
|
//
|
|
@@ -453,7 +405,6 @@ class Relayer {
|
|
|
453
405
|
this.hostname = void 0;
|
|
454
406
|
this.fetch = void 0;
|
|
455
407
|
this.path = '/rpc/Relayer/';
|
|
456
|
-
|
|
457
408
|
this.ping = headers => {
|
|
458
409
|
return this.fetch(this.url('Ping'), createHTTPRequest({}, headers)).then(res => {
|
|
459
410
|
return buildResponse(res).then(_data => {
|
|
@@ -463,7 +414,6 @@ class Relayer {
|
|
|
463
414
|
});
|
|
464
415
|
});
|
|
465
416
|
};
|
|
466
|
-
|
|
467
417
|
this.version = headers => {
|
|
468
418
|
return this.fetch(this.url('Version'), createHTTPRequest({}, headers)).then(res => {
|
|
469
419
|
return buildResponse(res).then(_data => {
|
|
@@ -473,7 +423,6 @@ class Relayer {
|
|
|
473
423
|
});
|
|
474
424
|
});
|
|
475
425
|
};
|
|
476
|
-
|
|
477
426
|
this.runtimeStatus = headers => {
|
|
478
427
|
return this.fetch(this.url('RuntimeStatus'), createHTTPRequest({}, headers)).then(res => {
|
|
479
428
|
return buildResponse(res).then(_data => {
|
|
@@ -483,7 +432,6 @@ class Relayer {
|
|
|
483
432
|
});
|
|
484
433
|
});
|
|
485
434
|
};
|
|
486
|
-
|
|
487
435
|
this.getSequenceContext = headers => {
|
|
488
436
|
return this.fetch(this.url('GetSequenceContext'), createHTTPRequest({}, headers)).then(res => {
|
|
489
437
|
return buildResponse(res).then(_data => {
|
|
@@ -493,7 +441,6 @@ class Relayer {
|
|
|
493
441
|
});
|
|
494
442
|
});
|
|
495
443
|
};
|
|
496
|
-
|
|
497
444
|
this.getChainID = headers => {
|
|
498
445
|
return this.fetch(this.url('GetChainID'), createHTTPRequest({}, headers)).then(res => {
|
|
499
446
|
return buildResponse(res).then(_data => {
|
|
@@ -503,7 +450,6 @@ class Relayer {
|
|
|
503
450
|
});
|
|
504
451
|
});
|
|
505
452
|
};
|
|
506
|
-
|
|
507
453
|
this.sendMetaTxn = (args, headers) => {
|
|
508
454
|
return this.fetch(this.url('SendMetaTxn'), createHTTPRequest(args, headers)).then(res => {
|
|
509
455
|
return buildResponse(res).then(_data => {
|
|
@@ -514,7 +460,6 @@ class Relayer {
|
|
|
514
460
|
});
|
|
515
461
|
});
|
|
516
462
|
};
|
|
517
|
-
|
|
518
463
|
this.getMetaTxnNonce = (args, headers) => {
|
|
519
464
|
return this.fetch(this.url('GetMetaTxnNonce'), createHTTPRequest(args, headers)).then(res => {
|
|
520
465
|
return buildResponse(res).then(_data => {
|
|
@@ -524,7 +469,6 @@ class Relayer {
|
|
|
524
469
|
});
|
|
525
470
|
});
|
|
526
471
|
};
|
|
527
|
-
|
|
528
472
|
this.getMetaTxnReceipt = (args, headers) => {
|
|
529
473
|
return this.fetch(this.url('GetMetaTxnReceipt'), createHTTPRequest(args, headers)).then(res => {
|
|
530
474
|
return buildResponse(res).then(_data => {
|
|
@@ -534,7 +478,6 @@ class Relayer {
|
|
|
534
478
|
});
|
|
535
479
|
});
|
|
536
480
|
};
|
|
537
|
-
|
|
538
481
|
this.simulate = (args, headers) => {
|
|
539
482
|
return this.fetch(this.url('Simulate'), createHTTPRequest(args, headers)).then(res => {
|
|
540
483
|
return buildResponse(res).then(_data => {
|
|
@@ -544,7 +487,15 @@ class Relayer {
|
|
|
544
487
|
});
|
|
545
488
|
});
|
|
546
489
|
};
|
|
547
|
-
|
|
490
|
+
this.updateMetaTxnGasLimits = (args, headers) => {
|
|
491
|
+
return this.fetch(this.url('UpdateMetaTxnGasLimits'), createHTTPRequest(args, headers)).then(res => {
|
|
492
|
+
return buildResponse(res).then(_data => {
|
|
493
|
+
return {
|
|
494
|
+
payload: _data.payload
|
|
495
|
+
};
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
};
|
|
548
499
|
this.feeTokens = headers => {
|
|
549
500
|
return this.fetch(this.url('FeeTokens'), createHTTPRequest({}, headers)).then(res => {
|
|
550
501
|
return buildResponse(res).then(_data => {
|
|
@@ -555,7 +506,6 @@ class Relayer {
|
|
|
555
506
|
});
|
|
556
507
|
});
|
|
557
508
|
};
|
|
558
|
-
|
|
559
509
|
this.feeOptions = (args, headers) => {
|
|
560
510
|
return this.fetch(this.url('FeeOptions'), createHTTPRequest(args, headers)).then(res => {
|
|
561
511
|
return buildResponse(res).then(_data => {
|
|
@@ -566,7 +516,15 @@ class Relayer {
|
|
|
566
516
|
});
|
|
567
517
|
});
|
|
568
518
|
};
|
|
569
|
-
|
|
519
|
+
this.getMetaTxnNetworkFeeOptions = (args, headers) => {
|
|
520
|
+
return this.fetch(this.url('GetMetaTxnNetworkFeeOptions'), createHTTPRequest(args, headers)).then(res => {
|
|
521
|
+
return buildResponse(res).then(_data => {
|
|
522
|
+
return {
|
|
523
|
+
options: _data.options
|
|
524
|
+
};
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
};
|
|
570
528
|
this.sentTransactions = (args, headers) => {
|
|
571
529
|
return this.fetch(this.url('SentTransactions'), createHTTPRequest(args, headers)).then(res => {
|
|
572
530
|
return buildResponse(res).then(_data => {
|
|
@@ -577,7 +535,6 @@ class Relayer {
|
|
|
577
535
|
});
|
|
578
536
|
});
|
|
579
537
|
};
|
|
580
|
-
|
|
581
538
|
this.pendingTransactions = (args, headers) => {
|
|
582
539
|
return this.fetch(this.url('PendingTransactions'), createHTTPRequest(args, headers)).then(res => {
|
|
583
540
|
return buildResponse(res).then(_data => {
|
|
@@ -588,7 +545,6 @@ class Relayer {
|
|
|
588
545
|
});
|
|
589
546
|
});
|
|
590
547
|
};
|
|
591
|
-
|
|
592
548
|
this.listGasSponsors = (args, headers) => {
|
|
593
549
|
return this.fetch(this.url('ListGasSponsors'), createHTTPRequest(args, headers)).then(res => {
|
|
594
550
|
return buildResponse(res).then(_data => {
|
|
@@ -599,7 +555,6 @@ class Relayer {
|
|
|
599
555
|
});
|
|
600
556
|
});
|
|
601
557
|
};
|
|
602
|
-
|
|
603
558
|
this.addGasSponsor = (args, headers) => {
|
|
604
559
|
return this.fetch(this.url('AddGasSponsor'), createHTTPRequest(args, headers)).then(res => {
|
|
605
560
|
return buildResponse(res).then(_data => {
|
|
@@ -610,7 +565,6 @@ class Relayer {
|
|
|
610
565
|
});
|
|
611
566
|
});
|
|
612
567
|
};
|
|
613
|
-
|
|
614
568
|
this.updateGasSponsor = (args, headers) => {
|
|
615
569
|
return this.fetch(this.url('UpdateGasSponsor'), createHTTPRequest(args, headers)).then(res => {
|
|
616
570
|
return buildResponse(res).then(_data => {
|
|
@@ -621,7 +575,6 @@ class Relayer {
|
|
|
621
575
|
});
|
|
622
576
|
});
|
|
623
577
|
};
|
|
624
|
-
|
|
625
578
|
this.reportGasSponsorUsage = (args, headers) => {
|
|
626
579
|
return this.fetch(this.url('ReportGasSponsorUsage'), createHTTPRequest(args, headers)).then(res => {
|
|
627
580
|
return buildResponse(res).then(_data => {
|
|
@@ -631,17 +584,13 @@ class Relayer {
|
|
|
631
584
|
});
|
|
632
585
|
});
|
|
633
586
|
};
|
|
634
|
-
|
|
635
587
|
this.hostname = hostname;
|
|
636
|
-
this.fetch = fetch;
|
|
588
|
+
this.fetch = (input, init) => fetch(input, init);
|
|
637
589
|
}
|
|
638
|
-
|
|
639
590
|
url(name) {
|
|
640
591
|
return this.hostname + this.path + name;
|
|
641
592
|
}
|
|
642
|
-
|
|
643
593
|
}
|
|
644
|
-
|
|
645
594
|
const createHTTPRequest = (body = {}, headers = {}) => {
|
|
646
595
|
return {
|
|
647
596
|
method: 'POST',
|
|
@@ -651,11 +600,9 @@ const createHTTPRequest = (body = {}, headers = {}) => {
|
|
|
651
600
|
body: JSON.stringify(body || {})
|
|
652
601
|
};
|
|
653
602
|
};
|
|
654
|
-
|
|
655
603
|
const buildResponse = res => {
|
|
656
604
|
return res.text().then(text => {
|
|
657
605
|
let data;
|
|
658
|
-
|
|
659
606
|
try {
|
|
660
607
|
data = JSON.parse(text);
|
|
661
608
|
} catch (err) {
|
|
@@ -665,7 +612,6 @@ const buildResponse = res => {
|
|
|
665
612
|
status: res.status
|
|
666
613
|
};
|
|
667
614
|
}
|
|
668
|
-
|
|
669
615
|
if (!res.ok) {
|
|
670
616
|
throw data; // webrpc error response
|
|
671
617
|
}
|
|
@@ -695,18 +641,15 @@ class RpcRelayer extends BaseRelayer {
|
|
|
695
641
|
constructor(options) {
|
|
696
642
|
super(options);
|
|
697
643
|
this.service = void 0;
|
|
698
|
-
this.service = new Relayer(options.url,
|
|
644
|
+
this.service = new Relayer(options.url, global.fetch);
|
|
699
645
|
}
|
|
700
|
-
|
|
701
646
|
async waitReceipt(metaTxnId, delay = 1000, maxFails = 5, isCancelled) {
|
|
702
647
|
if (typeof metaTxnId !== 'string') {
|
|
703
648
|
logger.info('computing id', metaTxnId.config, metaTxnId.context, metaTxnId.chainId, ...metaTxnId.transactions);
|
|
704
649
|
metaTxnId = computeMetaTxnHash(addressOf(metaTxnId.config, metaTxnId.context), metaTxnId.chainId, ...metaTxnId.transactions);
|
|
705
650
|
}
|
|
706
|
-
|
|
707
651
|
logger.info(`[rpc-relayer/waitReceipt] waiting for ${metaTxnId}`);
|
|
708
652
|
let fails = 0;
|
|
709
|
-
|
|
710
653
|
while (isCancelled === undefined || !isCancelled()) {
|
|
711
654
|
try {
|
|
712
655
|
const {
|
|
@@ -714,7 +657,6 @@ class RpcRelayer extends BaseRelayer {
|
|
|
714
657
|
} = await this.service.getMetaTxnReceipt({
|
|
715
658
|
metaTxID: metaTxnId
|
|
716
659
|
});
|
|
717
|
-
|
|
718
660
|
if (receipt && receipt.txnReceipt && receipt.txnReceipt !== 'null' && FINAL_STATUSES.includes(receipt.status)) {
|
|
719
661
|
return {
|
|
720
662
|
receipt
|
|
@@ -722,20 +664,16 @@ class RpcRelayer extends BaseRelayer {
|
|
|
722
664
|
}
|
|
723
665
|
} catch (e) {
|
|
724
666
|
fails++;
|
|
725
|
-
|
|
726
667
|
if (fails === maxFails) {
|
|
727
668
|
throw e;
|
|
728
669
|
}
|
|
729
670
|
}
|
|
730
|
-
|
|
731
671
|
if (isCancelled === undefined || !isCancelled()) {
|
|
732
672
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
733
673
|
}
|
|
734
674
|
}
|
|
735
|
-
|
|
736
675
|
throw new Error(`Cancelled waiting for transaction receipt ${metaTxnId}`);
|
|
737
676
|
}
|
|
738
|
-
|
|
739
677
|
async simulate(wallet, ...transactions) {
|
|
740
678
|
const coder = ethers.utils.defaultAbiCoder;
|
|
741
679
|
const encoded = coder.encode([MetaTransactionsType], [sequenceTxAbiEncode(transactions)]);
|
|
@@ -744,28 +682,23 @@ class RpcRelayer extends BaseRelayer {
|
|
|
744
682
|
transactions: encoded
|
|
745
683
|
})).results;
|
|
746
684
|
}
|
|
747
|
-
|
|
748
685
|
async getFeeOptions(config, context, ...transactions) {
|
|
749
686
|
// NOTE/TODO: for a given `service` the feeTokens will not change between execution, so we should memoize this value
|
|
750
687
|
// for a short-period of time, perhaps for 1 day or in memory. Perhaps one day we can make this happen automatically
|
|
751
688
|
// with http cache response for this endpoint and service-worker.. lots of approaches
|
|
752
689
|
const feeTokens = await this.service.feeTokens();
|
|
753
|
-
|
|
754
690
|
if (feeTokens.isFeeRequired) {
|
|
755
691
|
const symbols = feeTokens.tokens.map(token => token.symbol).join(', ');
|
|
756
692
|
logger.info(`[rpc-relayer/getFeeOptions] relayer fees are required, accepted tokens are ${symbols}`);
|
|
757
693
|
const wallet = addressOf(config, context);
|
|
758
694
|
let nonce = readSequenceNonce(...transactions);
|
|
759
|
-
|
|
760
695
|
if (nonce === undefined) {
|
|
761
696
|
nonce = await this.getNonce(config, context);
|
|
762
697
|
}
|
|
763
|
-
|
|
764
698
|
if (!this.provider) {
|
|
765
699
|
logger.warn(`[rpc-relayer/getFeeOptions] provider not set, needed for stub signature`);
|
|
766
700
|
throw new Error('provider is not set');
|
|
767
701
|
}
|
|
768
|
-
|
|
769
702
|
const {
|
|
770
703
|
to,
|
|
771
704
|
execute
|
|
@@ -801,14 +734,12 @@ class RpcRelayer extends BaseRelayer {
|
|
|
801
734
|
};
|
|
802
735
|
}
|
|
803
736
|
}
|
|
804
|
-
|
|
805
737
|
async gasRefundOptions(config, context, ...transactions) {
|
|
806
738
|
const {
|
|
807
739
|
options
|
|
808
740
|
} = await this.getFeeOptions(config, context, ...transactions);
|
|
809
741
|
return options;
|
|
810
742
|
}
|
|
811
|
-
|
|
812
743
|
async getNonce(config, context, space) {
|
|
813
744
|
const addr = addressOf(config, context);
|
|
814
745
|
logger.info(`[rpc-relayer/getNonce] get nonce for wallet ${addr} space: ${space}`);
|
|
@@ -822,13 +753,10 @@ class RpcRelayer extends BaseRelayer {
|
|
|
822
753
|
logger.info(`[rpc-relayer/getNonce] got next nonce for wallet ${addr} ${decodedNonce} space: ${decodedSpace}`);
|
|
823
754
|
return nonce;
|
|
824
755
|
}
|
|
825
|
-
|
|
826
756
|
async relay(signedTxs, quote, waitForReceipt = true) {
|
|
827
757
|
var _this = this;
|
|
828
|
-
|
|
829
758
|
logger.info(`[rpc-relayer/relay] relaying signed meta-transactions ${JSON.stringify(signedTxs)} with quote ${JSON.stringify(quote)}`);
|
|
830
759
|
let typecheckedQuote;
|
|
831
|
-
|
|
832
760
|
if (quote !== undefined) {
|
|
833
761
|
if (typeof quote._quote === 'string') {
|
|
834
762
|
typecheckedQuote = quote._quote;
|
|
@@ -836,12 +764,10 @@ class RpcRelayer extends BaseRelayer {
|
|
|
836
764
|
logger.warn('[rpc-relayer/relay] ignoring invalid fee quote');
|
|
837
765
|
}
|
|
838
766
|
}
|
|
839
|
-
|
|
840
767
|
if (!this.provider) {
|
|
841
768
|
logger.warn(`[rpc-relayer/relay] provider not set, failed relay`);
|
|
842
769
|
throw new Error('provider is not set');
|
|
843
770
|
}
|
|
844
|
-
|
|
845
771
|
const {
|
|
846
772
|
to: contract,
|
|
847
773
|
execute
|
|
@@ -858,7 +784,6 @@ class RpcRelayer extends BaseRelayer {
|
|
|
858
784
|
quote: typecheckedQuote
|
|
859
785
|
});
|
|
860
786
|
logger.info(`[rpc-relayer/relay] got relay result ${JSON.stringify(metaTxn)}`);
|
|
861
|
-
|
|
862
787
|
if (waitForReceipt) {
|
|
863
788
|
return this.wait(metaTxn.txnHash);
|
|
864
789
|
} else {
|
|
@@ -868,33 +793,25 @@ class RpcRelayer extends BaseRelayer {
|
|
|
868
793
|
from: walletAddress,
|
|
869
794
|
wait: _confirmations => Promise.reject(new Error('impossible'))
|
|
870
795
|
};
|
|
871
|
-
|
|
872
796
|
const wait = async function wait(confirmations) {
|
|
873
797
|
var _waitResponse$receipt;
|
|
874
|
-
|
|
875
798
|
if (!_this.provider) {
|
|
876
799
|
throw new Error('cannot wait for receipt, relayer has no provider set');
|
|
877
800
|
}
|
|
878
|
-
|
|
879
801
|
const waitResponse = await _this.wait(metaTxn.txnHash);
|
|
880
802
|
const transactionHash = (_waitResponse$receipt = waitResponse.receipt) == null ? void 0 : _waitResponse$receipt.transactionHash;
|
|
881
|
-
|
|
882
803
|
if (!transactionHash) {
|
|
883
804
|
throw new Error('cannot wait for receipt, unknown native transaction hash');
|
|
884
805
|
}
|
|
885
|
-
|
|
886
806
|
Object.assign(response, waitResponse);
|
|
887
807
|
return _this.provider.waitForTransaction(transactionHash, confirmations);
|
|
888
808
|
};
|
|
889
|
-
|
|
890
809
|
response.wait = wait;
|
|
891
810
|
return response;
|
|
892
811
|
}
|
|
893
812
|
}
|
|
894
|
-
|
|
895
813
|
async wait(metaTxnId, timeout, delay = 1000, maxFails = 5) {
|
|
896
814
|
var _this2 = this;
|
|
897
|
-
|
|
898
815
|
let timedOut = false;
|
|
899
816
|
const {
|
|
900
817
|
receipt
|
|
@@ -902,11 +819,9 @@ class RpcRelayer extends BaseRelayer {
|
|
|
902
819
|
timedOut = true;
|
|
903
820
|
reject(`Timeout waiting for transaction receipt ${metaTxnId}`);
|
|
904
821
|
}, timeout))]) : this.waitReceipt(metaTxnId, delay, maxFails));
|
|
905
|
-
|
|
906
822
|
if (!receipt.txnReceipt || FAILED_STATUSES.includes(receipt.status)) {
|
|
907
823
|
throw new MetaTransactionResponseException(receipt);
|
|
908
824
|
}
|
|
909
|
-
|
|
910
825
|
const txReceipt = JSON.parse(receipt.txnReceipt);
|
|
911
826
|
return {
|
|
912
827
|
blockHash: txReceipt.blockHash,
|
|
@@ -922,14 +837,11 @@ class RpcRelayer extends BaseRelayer {
|
|
|
922
837
|
}
|
|
923
838
|
};
|
|
924
839
|
}
|
|
925
|
-
|
|
926
840
|
}
|
|
927
|
-
|
|
928
841
|
class MetaTransactionResponseException {
|
|
929
842
|
constructor(receipt) {
|
|
930
843
|
this.receipt = receipt;
|
|
931
844
|
}
|
|
932
|
-
|
|
933
845
|
}
|
|
934
846
|
|
|
935
847
|
function isRelayer(cand) {
|