@0xsequence/relayer 0.43.34 → 1.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/dist/0xsequence-relayer.cjs.dev.js +91 -218
- package/dist/0xsequence-relayer.cjs.prod.js +91 -218
- package/dist/0xsequence-relayer.esm.js +92 -216
- package/dist/declarations/src/index.d.ts +11 -10
- package/dist/declarations/src/local-relayer.d.ts +8 -8
- package/dist/declarations/src/provider-relayer.d.ts +15 -14
- package/dist/declarations/src/rpc-relayer/index.d.ts +18 -13
- package/package.json +8 -8
- package/src/index.ts +18 -14
- package/src/local-relayer.ts +24 -38
- package/src/provider-relayer.ts +23 -32
- package/src/rpc-relayer/index.ts +70 -80
- package/dist/declarations/src/base-relayer.d.ts +0 -35
- package/src/base-relayer.ts +0 -136
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { ethers, providers,
|
|
1
|
+
import { ethers, providers, Signer } from 'ethers';
|
|
2
|
+
import { logger, getDefaultConnectionInfo } from '@0xsequence/utils';
|
|
2
3
|
import { walletContracts } from '@0xsequence/abi';
|
|
3
|
-
import {
|
|
4
|
-
import { isBigNumberish, logger } from '@0xsequence/utils';
|
|
5
|
-
import { imageHash, addressOf, encodeSignature, buildStubSignature } from '@0xsequence/config';
|
|
4
|
+
import { commons } from '@0xsequence/core';
|
|
6
5
|
|
|
7
6
|
function _extends() {
|
|
8
7
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
@@ -19,105 +18,6 @@ function _extends() {
|
|
|
19
18
|
return _extends.apply(this, arguments);
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
function isBaseRelayerOptions(obj) {
|
|
23
|
-
return obj.bundleCreation !== undefined && typeof obj.bundleCreation === 'boolean' || obj.creationGasLimit !== undefined && isBigNumberish(obj.creationGasLimit) || obj.provider !== undefined && (providers.Provider.isProvider(obj.provider) || typeof obj.provider === 'string');
|
|
24
|
-
}
|
|
25
|
-
const BaseRelayerDefaults = {
|
|
26
|
-
bundleCreation: true,
|
|
27
|
-
creationGasLimit: ethers.constants.Two.pow(17)
|
|
28
|
-
};
|
|
29
|
-
class BaseRelayer {
|
|
30
|
-
constructor(options) {
|
|
31
|
-
this.provider = void 0;
|
|
32
|
-
this.bundleCreation = void 0;
|
|
33
|
-
this.creationGasLimit = void 0;
|
|
34
|
-
const opts = _extends({}, BaseRelayerDefaults, options);
|
|
35
|
-
this.bundleCreation = opts.bundleCreation;
|
|
36
|
-
this.provider = opts.provider;
|
|
37
|
-
this.creationGasLimit = ethers.BigNumber.from(opts.creationGasLimit);
|
|
38
|
-
}
|
|
39
|
-
async isWalletDeployed(walletAddress) {
|
|
40
|
-
if (!this.provider) throw new Error('Bundled creation provider not found');
|
|
41
|
-
return (await this.provider.getCode(walletAddress)) !== '0x';
|
|
42
|
-
}
|
|
43
|
-
prepareWalletDeploy(config, context) {
|
|
44
|
-
const factoryInterface = new utils.Interface(walletContracts.factory.abi);
|
|
45
|
-
return {
|
|
46
|
-
to: context.factory,
|
|
47
|
-
data: factoryInterface.encodeFunctionData(factoryInterface.getFunction('deploy'), [context.mainModule, imageHash(config)])
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
async prependWalletDeploy(signedTransactions) {
|
|
51
|
-
const {
|
|
52
|
-
config,
|
|
53
|
-
context,
|
|
54
|
-
transactions,
|
|
55
|
-
nonce,
|
|
56
|
-
signature
|
|
57
|
-
} = signedTransactions;
|
|
58
|
-
const walletAddress = addressOf(config, context);
|
|
59
|
-
const walletInterface = new utils.Interface(walletContracts.mainModule.abi);
|
|
60
|
-
const encodedSignature = async function () {
|
|
61
|
-
const sig = await signature;
|
|
62
|
-
if (typeof sig === 'string') return sig;
|
|
63
|
-
return encodeSignature(sig);
|
|
64
|
-
}();
|
|
65
|
-
if (this.bundleCreation && !(await this.isWalletDeployed(walletAddress))) {
|
|
66
|
-
return {
|
|
67
|
-
to: context.guestModule,
|
|
68
|
-
execute: {
|
|
69
|
-
transactions: [_extends({}, this.prepareWalletDeploy(config, context), {
|
|
70
|
-
delegateCall: false,
|
|
71
|
-
revertOnError: false,
|
|
72
|
-
gasLimit: this.creationGasLimit,
|
|
73
|
-
value: ethers.constants.Zero
|
|
74
|
-
}), {
|
|
75
|
-
delegateCall: false,
|
|
76
|
-
revertOnError: true,
|
|
77
|
-
gasLimit: ethers.constants.Zero,
|
|
78
|
-
to: walletAddress,
|
|
79
|
-
value: ethers.constants.Zero,
|
|
80
|
-
data: walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(transactions), nonce, await encodedSignature])
|
|
81
|
-
}],
|
|
82
|
-
nonce: ethers.constants.Zero,
|
|
83
|
-
signature: '0x'
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
} else {
|
|
87
|
-
return {
|
|
88
|
-
to: walletAddress,
|
|
89
|
-
execute: {
|
|
90
|
-
transactions,
|
|
91
|
-
nonce: ethers.BigNumber.from(nonce),
|
|
92
|
-
signature: await encodedSignature
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
async prepareTransactions(config, context, signature, ...transactions) {
|
|
98
|
-
//, gasLimit?: ethers.BigNumberish }> {
|
|
99
|
-
const nonce = readSequenceNonce(...transactions);
|
|
100
|
-
if (!nonce) {
|
|
101
|
-
throw new Error('Unable to prepare transactions without a defined nonce');
|
|
102
|
-
}
|
|
103
|
-
const {
|
|
104
|
-
to,
|
|
105
|
-
execute
|
|
106
|
-
} = await this.prependWalletDeploy({
|
|
107
|
-
config,
|
|
108
|
-
context,
|
|
109
|
-
transactions,
|
|
110
|
-
nonce,
|
|
111
|
-
signature
|
|
112
|
-
});
|
|
113
|
-
const walletInterface = new utils.Interface(walletContracts.mainModule.abi);
|
|
114
|
-
return {
|
|
115
|
-
to,
|
|
116
|
-
data: walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature])
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
21
|
const DEFAULT_GAS_LIMIT = ethers.BigNumber.from(800000);
|
|
122
22
|
const ProviderRelayerDefaults = {
|
|
123
23
|
waitPollRate: 1000,
|
|
@@ -127,18 +27,10 @@ const ProviderRelayerDefaults = {
|
|
|
127
27
|
function isProviderRelayerOptions(obj) {
|
|
128
28
|
return obj.provider !== undefined && providers.Provider.isProvider(obj.provider);
|
|
129
29
|
}
|
|
130
|
-
class ProviderRelayer
|
|
30
|
+
class ProviderRelayer {
|
|
131
31
|
constructor(options) {
|
|
132
|
-
super(options);
|
|
133
|
-
this.provider = void 0;
|
|
134
|
-
this.waitPollRate = void 0;
|
|
135
|
-
this.deltaBlocksLog = void 0;
|
|
136
|
-
this.fromBlockLog = void 0;
|
|
137
32
|
const opts = _extends({}, ProviderRelayerDefaults, options);
|
|
138
33
|
this.provider = opts.provider;
|
|
139
|
-
this.waitPollRate = opts.waitPollRate;
|
|
140
|
-
this.deltaBlocksLog = opts.deltaBlocksLog;
|
|
141
|
-
this.fromBlockLog = opts.fromBlockLog;
|
|
142
34
|
}
|
|
143
35
|
async simulate(wallet, ...transactions) {
|
|
144
36
|
var _this = this;
|
|
@@ -154,7 +46,7 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
154
46
|
}
|
|
155
47
|
|
|
156
48
|
// Fee can't be estimated for self-called if wallet hasn't been deployed
|
|
157
|
-
if (tx.to === wallet &&
|
|
49
|
+
if (tx.to === wallet && (await _this.provider.getCode(wallet).then(code => ethers.utils.arrayify(code).length === 0))) {
|
|
158
50
|
return DEFAULT_GAS_LIMIT;
|
|
159
51
|
}
|
|
160
52
|
if (!_this.provider) {
|
|
@@ -176,28 +68,26 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
176
68
|
gasLimit: ethers.BigNumber.from(gasLimit).toNumber()
|
|
177
69
|
}));
|
|
178
70
|
}
|
|
179
|
-
async getNonce(
|
|
71
|
+
async getNonce(address, space, blockTag) {
|
|
180
72
|
if (!this.provider) {
|
|
181
73
|
throw new Error('provider is not set');
|
|
182
74
|
}
|
|
183
|
-
|
|
184
|
-
if ((await this.provider.getCode(addr)) === '0x') {
|
|
75
|
+
if ((await this.provider.getCode(address)) === '0x') {
|
|
185
76
|
return 0;
|
|
186
77
|
}
|
|
187
78
|
if (space === undefined) {
|
|
188
79
|
space = 0;
|
|
189
80
|
}
|
|
190
|
-
const module = new ethers.Contract(
|
|
81
|
+
const module = new ethers.Contract(address, walletContracts.mainModule.abi, this.provider);
|
|
191
82
|
const nonce = await module.readNonce(space, {
|
|
192
83
|
blockTag: blockTag
|
|
193
84
|
});
|
|
194
|
-
return encodeNonce(space, nonce);
|
|
85
|
+
return commons.transaction.encodeNonce(space, nonce);
|
|
195
86
|
}
|
|
196
87
|
async wait(metaTxnId, timeout, delay = this.waitPollRate, maxFails = 5) {
|
|
197
88
|
var _this2 = this;
|
|
198
89
|
if (typeof metaTxnId !== 'string') {
|
|
199
|
-
|
|
200
|
-
metaTxnId = computeMetaTxnHash(addressOf(metaTxnId.config, metaTxnId.context), metaTxnId.chainId, ...metaTxnId.transactions);
|
|
90
|
+
metaTxnId = commons.transaction.intendedTransactionID(metaTxnId);
|
|
201
91
|
}
|
|
202
92
|
let timedOut = false;
|
|
203
93
|
const retry = async function retry(f, errorMessage) {
|
|
@@ -285,31 +175,23 @@ class LocalRelayer extends ProviderRelayer {
|
|
|
285
175
|
} : _extends({}, options, {
|
|
286
176
|
provider: options.signer.provider
|
|
287
177
|
}));
|
|
288
|
-
this.signer = void 0;
|
|
289
|
-
this.txnOptions = void 0;
|
|
290
178
|
this.signer = Signer.isSigner(options) ? options : options.signer;
|
|
291
179
|
if (!this.signer.provider) throw new Error("Signer must have a provider");
|
|
292
180
|
}
|
|
293
|
-
async
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const walletDeployTxn = this.prepareWalletDeploy(config, context);
|
|
298
|
-
|
|
299
|
-
// NOTE: for hardhat to pass, we have to set the gasLimit directly, as its unable to estimate
|
|
300
|
-
return this.signer.sendTransaction(_extends({}, walletDeployTxn, {
|
|
301
|
-
gasLimit: ethers.constants.Two.pow(17)
|
|
302
|
-
}));
|
|
181
|
+
async getFeeOptions(_address, ..._transactions) {
|
|
182
|
+
return {
|
|
183
|
+
options: []
|
|
184
|
+
};
|
|
303
185
|
}
|
|
304
|
-
async
|
|
186
|
+
async getFeeOptionsRaw(_entrypoint, _data) {
|
|
305
187
|
return {
|
|
306
188
|
options: []
|
|
307
189
|
};
|
|
308
190
|
}
|
|
309
|
-
async gasRefundOptions(
|
|
191
|
+
async gasRefundOptions(address, ...transactions) {
|
|
310
192
|
const {
|
|
311
193
|
options
|
|
312
|
-
} = await this.getFeeOptions(
|
|
194
|
+
} = await this.getFeeOptions(address, ...transactions);
|
|
313
195
|
return options;
|
|
314
196
|
}
|
|
315
197
|
setTransactionOptions(transactionRequest) {
|
|
@@ -319,15 +201,7 @@ class LocalRelayer extends ProviderRelayer {
|
|
|
319
201
|
if (quote !== undefined) {
|
|
320
202
|
logger.warn(`LocalRelayer doesn't accept fee quotes`);
|
|
321
203
|
}
|
|
322
|
-
|
|
323
|
-
throw new Error('LocalRelayer requires the context.guestModule address');
|
|
324
|
-
}
|
|
325
|
-
const {
|
|
326
|
-
to,
|
|
327
|
-
execute
|
|
328
|
-
} = await this.prependWalletDeploy(signedTxs);
|
|
329
|
-
const walletInterface = new ethers.utils.Interface(walletContracts.mainModule.abi);
|
|
330
|
-
const data = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
204
|
+
const data = commons.transaction.encodeBundleExecData(signedTxs);
|
|
331
205
|
|
|
332
206
|
// TODO: think about computing gas limit individually, summing together and passing across
|
|
333
207
|
// NOTE: we expect that all txns have set their gasLimit ahead of time through proper estimation
|
|
@@ -335,9 +209,11 @@ class LocalRelayer extends ProviderRelayer {
|
|
|
335
209
|
// txRequest.gasLimit = gasLimit
|
|
336
210
|
|
|
337
211
|
const responsePromise = this.signer.sendTransaction(_extends({
|
|
338
|
-
to,
|
|
212
|
+
to: signedTxs.entrypoint,
|
|
339
213
|
data
|
|
340
|
-
}, this.txnOptions
|
|
214
|
+
}, this.txnOptions, {
|
|
215
|
+
gasLimit: 9000000
|
|
216
|
+
}));
|
|
341
217
|
if (waitForReceipt) {
|
|
342
218
|
const response = await responsePromise;
|
|
343
219
|
response.receipt = await response.wait();
|
|
@@ -368,8 +244,7 @@ const WebRPCSchemaHash = "752f4f4274ca80d2fd974b5b44ed8245dfe40554";
|
|
|
368
244
|
// Types
|
|
369
245
|
//
|
|
370
246
|
|
|
371
|
-
let ETHTxnStatus
|
|
372
|
-
(function (ETHTxnStatus) {
|
|
247
|
+
let ETHTxnStatus = /*#__PURE__*/function (ETHTxnStatus) {
|
|
373
248
|
ETHTxnStatus["UNKNOWN"] = "UNKNOWN";
|
|
374
249
|
ETHTxnStatus["DROPPED"] = "DROPPED";
|
|
375
250
|
ETHTxnStatus["QUEUED"] = "QUEUED";
|
|
@@ -377,34 +252,33 @@ let ETHTxnStatus;
|
|
|
377
252
|
ETHTxnStatus["SUCCEEDED"] = "SUCCEEDED";
|
|
378
253
|
ETHTxnStatus["PARTIALLY_FAILED"] = "PARTIALLY_FAILED";
|
|
379
254
|
ETHTxnStatus["FAILED"] = "FAILED";
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
255
|
+
return ETHTxnStatus;
|
|
256
|
+
}({});
|
|
257
|
+
let TransferType = /*#__PURE__*/function (TransferType) {
|
|
383
258
|
TransferType["SEND"] = "SEND";
|
|
384
259
|
TransferType["RECEIVE"] = "RECEIVE";
|
|
385
260
|
TransferType["BRIDGE_DEPOSIT"] = "BRIDGE_DEPOSIT";
|
|
386
261
|
TransferType["BRIDGE_WITHDRAW"] = "BRIDGE_WITHDRAW";
|
|
387
262
|
TransferType["BURN"] = "BURN";
|
|
388
263
|
TransferType["UNKNOWN"] = "UNKNOWN";
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
264
|
+
return TransferType;
|
|
265
|
+
}({});
|
|
266
|
+
let FeeTokenType = /*#__PURE__*/function (FeeTokenType) {
|
|
392
267
|
FeeTokenType["UNKNOWN"] = "UNKNOWN";
|
|
393
268
|
FeeTokenType["ERC20_TOKEN"] = "ERC20_TOKEN";
|
|
394
269
|
FeeTokenType["ERC1155_TOKEN"] = "ERC1155_TOKEN";
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
270
|
+
return FeeTokenType;
|
|
271
|
+
}({});
|
|
272
|
+
let SortOrder = /*#__PURE__*/function (SortOrder) {
|
|
398
273
|
SortOrder["DESC"] = "DESC";
|
|
399
274
|
SortOrder["ASC"] = "ASC";
|
|
400
|
-
|
|
275
|
+
return SortOrder;
|
|
276
|
+
}({});
|
|
401
277
|
//
|
|
402
278
|
// Client
|
|
403
279
|
//
|
|
404
280
|
class Relayer {
|
|
405
281
|
constructor(hostname, fetch) {
|
|
406
|
-
this.hostname = void 0;
|
|
407
|
-
this.fetch = void 0;
|
|
408
282
|
this.path = '/rpc/Relayer/';
|
|
409
283
|
this.ping = headers => {
|
|
410
284
|
return this.fetch(this.url('Ping'), createHTTPRequest({}, headers)).then(res => {
|
|
@@ -626,29 +500,27 @@ var relayer_gen = /*#__PURE__*/Object.freeze({
|
|
|
626
500
|
WebRPCVersion: WebRPCVersion,
|
|
627
501
|
WebRPCSchemaVersion: WebRPCSchemaVersion,
|
|
628
502
|
WebRPCSchemaHash: WebRPCSchemaHash,
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
503
|
+
ETHTxnStatus: ETHTxnStatus,
|
|
504
|
+
TransferType: TransferType,
|
|
505
|
+
FeeTokenType: FeeTokenType,
|
|
506
|
+
SortOrder: SortOrder,
|
|
633
507
|
Relayer: Relayer
|
|
634
508
|
});
|
|
635
509
|
|
|
636
510
|
const FINAL_STATUSES = [ETHTxnStatus.DROPPED, ETHTxnStatus.SUCCEEDED, ETHTxnStatus.PARTIALLY_FAILED, ETHTxnStatus.FAILED];
|
|
637
511
|
const FAILED_STATUSES = [ETHTxnStatus.DROPPED, ETHTxnStatus.PARTIALLY_FAILED, ETHTxnStatus.FAILED];
|
|
638
512
|
function isRpcRelayerOptions(obj) {
|
|
639
|
-
return obj.url !== undefined && typeof obj.url === 'string';
|
|
513
|
+
return obj.url !== undefined && typeof obj.url === 'string' && obj.provider !== undefined && ethers.providers.Provider.isProvider(obj.provider);
|
|
640
514
|
}
|
|
641
515
|
const fetch = typeof global === 'object' ? global.fetch : window.fetch;
|
|
642
|
-
class RpcRelayer
|
|
516
|
+
class RpcRelayer {
|
|
643
517
|
constructor(options) {
|
|
644
|
-
super(options);
|
|
645
|
-
this.service = void 0;
|
|
646
518
|
this.service = new Relayer(options.url, fetch);
|
|
519
|
+
this.provider = ethers.providers.Provider.isProvider(options.provider) ? options.provider : new ethers.providers.StaticJsonRpcProvider(getDefaultConnectionInfo(options.provider.url));
|
|
647
520
|
}
|
|
648
521
|
async waitReceipt(metaTxnId, delay = 1000, maxFails = 5, isCancelled) {
|
|
649
522
|
if (typeof metaTxnId !== 'string') {
|
|
650
|
-
|
|
651
|
-
metaTxnId = computeMetaTxnHash(addressOf(metaTxnId.config, metaTxnId.context), metaTxnId.chainId, ...metaTxnId.transactions);
|
|
523
|
+
metaTxnId = commons.transaction.intendedTransactionID(metaTxnId);
|
|
652
524
|
}
|
|
653
525
|
logger.info(`[rpc-relayer/waitReceipt] waiting for ${metaTxnId}`);
|
|
654
526
|
let fails = 0;
|
|
@@ -678,13 +550,13 @@ class RpcRelayer extends BaseRelayer {
|
|
|
678
550
|
}
|
|
679
551
|
async simulate(wallet, ...transactions) {
|
|
680
552
|
const coder = ethers.utils.defaultAbiCoder;
|
|
681
|
-
const encoded = coder.encode([MetaTransactionsType], [sequenceTxAbiEncode(transactions)]);
|
|
553
|
+
const encoded = coder.encode([commons.transaction.MetaTransactionsType], [commons.transaction.sequenceTxAbiEncode(transactions)]);
|
|
682
554
|
return (await this.service.simulate({
|
|
683
555
|
wallet,
|
|
684
556
|
transactions: encoded
|
|
685
557
|
})).results;
|
|
686
558
|
}
|
|
687
|
-
async getFeeOptions(
|
|
559
|
+
async getFeeOptions(address, ...transactions) {
|
|
688
560
|
// NOTE/TODO: for a given `service` the feeTokens will not change between execution, so we should memoize this value
|
|
689
561
|
// for a short-period of time, perhaps for 1 day or in memory. Perhaps one day we can make this happen automatically
|
|
690
562
|
// with http cache response for this endpoint and service-worker.. lots of approaches
|
|
@@ -692,34 +564,22 @@ class RpcRelayer extends BaseRelayer {
|
|
|
692
564
|
if (feeTokens.isFeeRequired) {
|
|
693
565
|
const symbols = feeTokens.tokens.map(token => token.symbol).join(', ');
|
|
694
566
|
logger.info(`[rpc-relayer/getFeeOptions] relayer fees are required, accepted tokens are ${symbols}`);
|
|
695
|
-
const
|
|
696
|
-
let nonce = readSequenceNonce(...transactions);
|
|
697
|
-
if (nonce === undefined) {
|
|
698
|
-
nonce = await this.getNonce(config, context);
|
|
699
|
-
}
|
|
567
|
+
const nonce = await this.getNonce(address);
|
|
700
568
|
if (!this.provider) {
|
|
701
569
|
logger.warn(`[rpc-relayer/getFeeOptions] provider not set, needed for stub signature`);
|
|
702
570
|
throw new Error('provider is not set');
|
|
703
571
|
}
|
|
704
|
-
const {
|
|
705
|
-
to,
|
|
706
|
-
execute
|
|
707
|
-
} = await this.prependWalletDeploy({
|
|
708
|
-
config,
|
|
709
|
-
context,
|
|
710
|
-
transactions,
|
|
711
|
-
nonce,
|
|
712
|
-
signature: buildStubSignature(this.provider, config)
|
|
713
|
-
});
|
|
714
|
-
const walletInterface = new ethers.utils.Interface(walletContracts.mainModule.abi);
|
|
715
|
-
const data = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
716
572
|
const {
|
|
717
573
|
options,
|
|
718
574
|
quote
|
|
719
575
|
} = await this.service.feeOptions({
|
|
720
|
-
wallet,
|
|
721
|
-
to,
|
|
722
|
-
data
|
|
576
|
+
wallet: address,
|
|
577
|
+
to: address,
|
|
578
|
+
data: commons.transaction.encodeBundleExecData({
|
|
579
|
+
entrypoint: address,
|
|
580
|
+
transactions,
|
|
581
|
+
nonce
|
|
582
|
+
})
|
|
723
583
|
});
|
|
724
584
|
logger.info(`[rpc-relayer/getFeeOptions] got refund options ${JSON.stringify(options)}`);
|
|
725
585
|
return {
|
|
@@ -736,23 +596,39 @@ class RpcRelayer extends BaseRelayer {
|
|
|
736
596
|
};
|
|
737
597
|
}
|
|
738
598
|
}
|
|
739
|
-
async
|
|
599
|
+
async getFeeOptionsRaw(entrypoint, data) {
|
|
600
|
+
const {
|
|
601
|
+
options,
|
|
602
|
+
quote
|
|
603
|
+
} = await this.service.feeOptions({
|
|
604
|
+
wallet: entrypoint,
|
|
605
|
+
to: entrypoint,
|
|
606
|
+
data: ethers.utils.hexlify(data)
|
|
607
|
+
});
|
|
608
|
+
return {
|
|
609
|
+
options,
|
|
610
|
+
quote: {
|
|
611
|
+
_tag: 'FeeQuote',
|
|
612
|
+
_quote: quote
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
async gasRefundOptions(address, ...transactions) {
|
|
740
617
|
const {
|
|
741
618
|
options
|
|
742
|
-
} = await this.getFeeOptions(
|
|
619
|
+
} = await this.getFeeOptions(address, ...transactions);
|
|
743
620
|
return options;
|
|
744
621
|
}
|
|
745
|
-
async getNonce(
|
|
746
|
-
|
|
747
|
-
logger.info(`[rpc-relayer/getNonce] get nonce for wallet ${addr} space: ${space}`);
|
|
622
|
+
async getNonce(address, space) {
|
|
623
|
+
logger.info(`[rpc-relayer/getNonce] get nonce for wallet ${address} space: ${space}`);
|
|
748
624
|
const encodedNonce = space !== undefined ? ethers.BigNumber.from(space).toHexString() : undefined;
|
|
749
625
|
const resp = await this.service.getMetaTxnNonce({
|
|
750
|
-
walletContractAddress:
|
|
626
|
+
walletContractAddress: address,
|
|
751
627
|
space: encodedNonce
|
|
752
628
|
});
|
|
753
629
|
const nonce = ethers.BigNumber.from(resp.nonce);
|
|
754
|
-
const [decodedSpace, decodedNonce] = decodeNonce(nonce);
|
|
755
|
-
logger.info(`[rpc-relayer/getNonce] got next nonce for wallet ${
|
|
630
|
+
const [decodedSpace, decodedNonce] = commons.transaction.decodeNonce(nonce);
|
|
631
|
+
logger.info(`[rpc-relayer/getNonce] got next nonce for wallet ${address} ${decodedNonce} space: ${decodedSpace}`);
|
|
756
632
|
return nonce;
|
|
757
633
|
}
|
|
758
634
|
async relay(signedTxs, quote, waitForReceipt = true) {
|
|
@@ -770,29 +646,23 @@ class RpcRelayer extends BaseRelayer {
|
|
|
770
646
|
logger.warn(`[rpc-relayer/relay] provider not set, failed relay`);
|
|
771
647
|
throw new Error('provider is not set');
|
|
772
648
|
}
|
|
773
|
-
const
|
|
774
|
-
to: contract,
|
|
775
|
-
execute
|
|
776
|
-
} = await this.prependWalletDeploy(signedTxs);
|
|
777
|
-
const walletAddress = addressOf(signedTxs.config, signedTxs.context);
|
|
778
|
-
const walletInterface = new ethers.utils.Interface(walletContracts.mainModule.abi);
|
|
779
|
-
const input = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
649
|
+
const data = commons.transaction.encodeBundleExecData(signedTxs);
|
|
780
650
|
const metaTxn = await this.service.sendMetaTxn({
|
|
781
651
|
call: {
|
|
782
|
-
walletAddress,
|
|
783
|
-
contract,
|
|
784
|
-
input
|
|
652
|
+
walletAddress: signedTxs.intent.wallet,
|
|
653
|
+
contract: signedTxs.entrypoint,
|
|
654
|
+
input: data
|
|
785
655
|
},
|
|
786
656
|
quote: typecheckedQuote
|
|
787
657
|
});
|
|
788
658
|
logger.info(`[rpc-relayer/relay] got relay result ${JSON.stringify(metaTxn)}`);
|
|
789
659
|
if (waitForReceipt) {
|
|
790
|
-
return this.wait(
|
|
660
|
+
return this.wait(signedTxs.intent.id);
|
|
791
661
|
} else {
|
|
792
662
|
const response = {
|
|
793
|
-
hash:
|
|
663
|
+
hash: signedTxs.intent.id,
|
|
794
664
|
confirmations: 0,
|
|
795
|
-
from:
|
|
665
|
+
from: signedTxs.intent.wallet,
|
|
796
666
|
wait: _confirmations => Promise.reject(new Error('impossible'))
|
|
797
667
|
};
|
|
798
668
|
const wait = async function wait(confirmations) {
|
|
@@ -800,7 +670,7 @@ class RpcRelayer extends BaseRelayer {
|
|
|
800
670
|
if (!_this.provider) {
|
|
801
671
|
throw new Error('cannot wait for receipt, relayer has no provider set');
|
|
802
672
|
}
|
|
803
|
-
const waitResponse = await _this.wait(
|
|
673
|
+
const waitResponse = await _this.wait(signedTxs.intent.id);
|
|
804
674
|
const transactionHash = (_waitResponse$receipt = waitResponse.receipt) == null ? void 0 : _waitResponse$receipt.transactionHash;
|
|
805
675
|
if (!transactionHash) {
|
|
806
676
|
throw new Error('cannot wait for receipt, unknown native transaction hash');
|
|
@@ -829,7 +699,7 @@ class RpcRelayer extends BaseRelayer {
|
|
|
829
699
|
blockHash: txReceipt.blockHash,
|
|
830
700
|
blockNumber: ethers.BigNumber.from(txReceipt.blockNumber).toNumber(),
|
|
831
701
|
confirmations: 1,
|
|
832
|
-
from: typeof metaTxnId === 'string' ? undefined :
|
|
702
|
+
from: typeof metaTxnId === 'string' ? undefined : metaTxnId.intent.wallet,
|
|
833
703
|
hash: txReceipt.transactionHash,
|
|
834
704
|
raw: receipt.txnReceipt,
|
|
835
705
|
receipt: txReceipt,
|
|
@@ -846,8 +716,14 @@ class MetaTransactionResponseException {
|
|
|
846
716
|
}
|
|
847
717
|
}
|
|
848
718
|
|
|
719
|
+
// A fee quote is simply an opaque value that can be obtained via Relayer.getFeeOptions(), and
|
|
720
|
+
// returned back to the same relayer via Relayer.relay(). Fee quotes should be treated as an
|
|
721
|
+
// implementation detail of the relayer that produces them.
|
|
722
|
+
//
|
|
723
|
+
// This interface exists for type-safety purposes to protect against passing non-FeeQuotes to
|
|
724
|
+
// Relayer.relay(), or any other functions that call it indirectly (e.g. Account.sendTransaction).
|
|
849
725
|
function isRelayer(cand) {
|
|
850
726
|
return typeof cand === 'object' && typeof cand.simulate === 'function' && typeof cand.getFeeOptions === 'function' && typeof cand.gasRefundOptions === 'function' && typeof cand.getNonce === 'function' && typeof cand.relay === 'function' && typeof cand.wait === 'function';
|
|
851
727
|
}
|
|
852
728
|
|
|
853
|
-
export {
|
|
729
|
+
export { LocalRelayer, ProviderRelayer, ProviderRelayerDefaults, RpcRelayer, relayer_gen as RpcRelayerProto, isLocalRelayerOptions, isProviderRelayerOptions, isRelayer, isRpcRelayerOptions, relayer_gen as proto };
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { ethers, providers } from 'ethers';
|
|
2
|
-
import { SignedTransactions, Transaction, TransactionResponse } from '@0xsequence/transactions';
|
|
3
|
-
import { WalletContext } from '@0xsequence/network';
|
|
4
|
-
import { WalletConfig } from '@0xsequence/config';
|
|
5
2
|
import { proto } from './rpc-relayer';
|
|
3
|
+
import { commons } from '@0xsequence/core';
|
|
6
4
|
export interface Relayer {
|
|
7
|
-
simulate(wallet: string, ...transactions: Transaction[]): Promise<SimulateResult[]>;
|
|
8
|
-
getFeeOptions(
|
|
5
|
+
simulate(wallet: string, ...transactions: commons.transaction.Transaction[]): Promise<SimulateResult[]>;
|
|
6
|
+
getFeeOptions(address: string, ...transactions: commons.transaction.Transaction[]): Promise<{
|
|
9
7
|
options: FeeOption[];
|
|
10
8
|
quote?: FeeQuote;
|
|
11
9
|
}>;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
getFeeOptionsRaw(entrypoint: string, data: ethers.utils.BytesLike): Promise<{
|
|
11
|
+
options: FeeOption[];
|
|
12
|
+
quote?: FeeQuote;
|
|
13
|
+
}>;
|
|
14
|
+
gasRefundOptions(address: string, ...transactions: commons.transaction.Transaction[]): Promise<FeeOption[]>;
|
|
15
|
+
getNonce(address: string, space?: ethers.BigNumberish, blockTag?: providers.BlockTag): Promise<ethers.BigNumberish>;
|
|
16
|
+
relay(signedTxs: commons.transaction.IntendedTransactionBundle, quote?: FeeQuote, waitForReceipt?: boolean): Promise<commons.transaction.TransactionResponse>;
|
|
17
|
+
wait(metaTxnId: string | commons.transaction.SignedTransactionBundle, timeout?: number, delay?: number, maxFails?: number): Promise<commons.transaction.TransactionResponse>;
|
|
16
18
|
}
|
|
17
19
|
export * from './local-relayer';
|
|
18
|
-
export * from './base-relayer';
|
|
19
20
|
export * from './provider-relayer';
|
|
20
21
|
export * from './rpc-relayer';
|
|
21
22
|
export { proto as RpcRelayerProto } from './rpc-relayer';
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { Signer as AbstractSigner, providers } from 'ethers';
|
|
2
|
-
import { SignedTransactions, Transaction, TransactionResponse } from '@0xsequence/transactions';
|
|
3
|
-
import { WalletContext } from '@0xsequence/network';
|
|
4
|
-
import { WalletConfig } from '@0xsequence/config';
|
|
1
|
+
import { Signer as AbstractSigner, providers, BytesLike } from 'ethers';
|
|
5
2
|
import { FeeOption, FeeQuote, Relayer } from '.';
|
|
6
3
|
import { ProviderRelayer, ProviderRelayerOptions } from './provider-relayer';
|
|
4
|
+
import { commons } from '@0xsequence/core';
|
|
7
5
|
export type LocalRelayerOptions = Omit<ProviderRelayerOptions, "provider"> & {
|
|
8
6
|
signer: AbstractSigner;
|
|
9
7
|
};
|
|
@@ -12,11 +10,13 @@ export declare class LocalRelayer extends ProviderRelayer implements Relayer {
|
|
|
12
10
|
private signer;
|
|
13
11
|
private txnOptions;
|
|
14
12
|
constructor(options: LocalRelayerOptions | AbstractSigner);
|
|
15
|
-
|
|
16
|
-
getFeeOptions(_config: WalletConfig, _context: WalletContext, ..._transactions: Transaction[]): Promise<{
|
|
13
|
+
getFeeOptions(_address: string, ..._transactions: commons.transaction.Transaction[]): Promise<{
|
|
17
14
|
options: FeeOption[];
|
|
18
15
|
}>;
|
|
19
|
-
|
|
16
|
+
getFeeOptionsRaw(_entrypoint: string, _data: BytesLike): Promise<{
|
|
17
|
+
options: FeeOption[];
|
|
18
|
+
}>;
|
|
19
|
+
gasRefundOptions(address: string, ...transactions: commons.transaction.Transaction[]): Promise<FeeOption[]>;
|
|
20
20
|
setTransactionOptions(transactionRequest: providers.TransactionRequest): void;
|
|
21
|
-
relay(signedTxs:
|
|
21
|
+
relay(signedTxs: commons.transaction.IntendedTransactionBundle, quote?: FeeQuote, waitForReceipt?: boolean): Promise<commons.transaction.TransactionResponse<providers.TransactionReceipt>>;
|
|
22
22
|
}
|
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
import { ethers, providers } from 'ethers';
|
|
2
|
-
import { SignedTransactions, Transaction, TransactionResponse } from '@0xsequence/transactions';
|
|
3
|
-
import { WalletContext } from '@0xsequence/network';
|
|
4
|
-
import { WalletConfig } from '@0xsequence/config';
|
|
5
|
-
import { BaseRelayer, BaseRelayerOptions } from './base-relayer';
|
|
6
2
|
import { FeeOption, FeeQuote, Relayer, SimulateResult } from '.';
|
|
7
|
-
import { Optionals
|
|
8
|
-
|
|
3
|
+
import { Optionals } from '@0xsequence/utils';
|
|
4
|
+
import { commons } from '@0xsequence/core';
|
|
5
|
+
export interface ProviderRelayerOptions {
|
|
9
6
|
provider: providers.Provider;
|
|
10
7
|
waitPollRate?: number;
|
|
11
8
|
deltaBlocksLog?: number;
|
|
12
9
|
fromBlockLog?: number;
|
|
13
10
|
}
|
|
14
|
-
export declare const ProviderRelayerDefaults: Required<Optionals<
|
|
11
|
+
export declare const ProviderRelayerDefaults: Required<Optionals<ProviderRelayerOptions>>;
|
|
15
12
|
export declare function isProviderRelayerOptions(obj: any): obj is ProviderRelayerOptions;
|
|
16
|
-
export declare abstract class ProviderRelayer
|
|
13
|
+
export declare abstract class ProviderRelayer implements Relayer {
|
|
17
14
|
provider: providers.Provider;
|
|
18
15
|
waitPollRate: number;
|
|
19
16
|
deltaBlocksLog: number;
|
|
20
17
|
fromBlockLog: number;
|
|
21
18
|
constructor(options: ProviderRelayerOptions);
|
|
22
|
-
abstract getFeeOptions(
|
|
19
|
+
abstract getFeeOptions(address: string, ...transactions: commons.transaction.Transaction[]): Promise<{
|
|
23
20
|
options: FeeOption[];
|
|
24
21
|
quote?: FeeQuote;
|
|
25
22
|
}>;
|
|
26
|
-
abstract
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
abstract getFeeOptionsRaw(entrypoint: string, data: ethers.utils.BytesLike): Promise<{
|
|
24
|
+
options: FeeOption[];
|
|
25
|
+
quote?: FeeQuote;
|
|
26
|
+
}>;
|
|
27
|
+
abstract gasRefundOptions(address: string, ...transactions: commons.transaction.Transaction[]): Promise<FeeOption[]>;
|
|
28
|
+
abstract relay(signedTxs: commons.transaction.IntendedTransactionBundle, quote?: FeeQuote, waitForReceipt?: boolean): Promise<commons.transaction.TransactionResponse>;
|
|
29
|
+
simulate(wallet: string, ...transactions: commons.transaction.Transaction[]): Promise<SimulateResult[]>;
|
|
30
|
+
getNonce(address: string, space?: ethers.BigNumberish, blockTag?: providers.BlockTag): Promise<ethers.BigNumberish>;
|
|
31
|
+
wait(metaTxnId: string | commons.transaction.SignedTransactionBundle, timeout?: number, delay?: number, maxFails?: number): Promise<providers.TransactionResponse & {
|
|
31
32
|
receipt: providers.TransactionReceipt;
|
|
32
33
|
}>;
|
|
33
34
|
}
|