@0xsequence/relayer 0.31.0 → 0.35.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/CHANGELOG.md +49 -0
- package/dist/0xsequence-relayer.cjs.dev.js +153 -48
- package/dist/0xsequence-relayer.cjs.prod.js +153 -48
- package/dist/0xsequence-relayer.esm.js +155 -50
- package/dist/declarations/src/base-relayer.d.ts +9 -1
- package/dist/declarations/src/index.d.ts +2 -0
- package/dist/declarations/src/provider-relayer.d.ts +2 -1
- package/dist/declarations/src/rpc-relayer/index.d.ts +2 -1
- package/dist/declarations/src/rpc-relayer/relayer.gen.d.ts +32 -1
- package/package.json +7 -7
- package/src/base-relayer.ts +38 -19
- package/src/index.ts +3 -0
- package/src/local-relayer.ts +11 -3
- package/src/provider-relayer.ts +19 -15
- package/src/rpc-relayer/index.ts +46 -28
- package/src/rpc-relayer/relayer.gen.ts +54 -2
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var ethers = require('ethers');
|
|
6
|
-
var providers = require('@ethersproject/providers');
|
|
7
6
|
var abi = require('@0xsequence/abi');
|
|
8
7
|
var transactions = require('@0xsequence/transactions');
|
|
8
|
+
var providers = require('@ethersproject/providers');
|
|
9
9
|
var config = require('@0xsequence/config');
|
|
10
10
|
var utils$1 = require('ethers/lib/utils');
|
|
11
11
|
var utils = require('@0xsequence/utils');
|
|
@@ -66,8 +66,14 @@ class BaseRelayer {
|
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
async
|
|
70
|
-
|
|
69
|
+
async prependWalletDeploy(signedTransactions) {
|
|
70
|
+
const {
|
|
71
|
+
config: config$1,
|
|
72
|
+
context,
|
|
73
|
+
transactions: transactions$1,
|
|
74
|
+
nonce,
|
|
75
|
+
signature
|
|
76
|
+
} = signedTransactions;
|
|
71
77
|
const walletAddress = config.addressOf(config$1, context);
|
|
72
78
|
const walletInterface = new utils$1.Interface(abi.walletContracts.mainModule.abi);
|
|
73
79
|
|
|
@@ -80,28 +86,61 @@ class BaseRelayer {
|
|
|
80
86
|
if (this.bundleCreation && !(await this.isWalletDeployed(walletAddress))) {
|
|
81
87
|
return {
|
|
82
88
|
to: context.guestModule,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
execute: {
|
|
90
|
+
transactions: [_extends({}, this.prepareWalletDeploy(config$1, context), {
|
|
91
|
+
delegateCall: false,
|
|
92
|
+
revertOnError: false,
|
|
93
|
+
gasLimit: this.creationGasLimit,
|
|
94
|
+
value: ethers.ethers.constants.Zero
|
|
95
|
+
}), {
|
|
96
|
+
delegateCall: false,
|
|
97
|
+
revertOnError: true,
|
|
98
|
+
gasLimit: ethers.ethers.constants.Zero,
|
|
99
|
+
to: walletAddress,
|
|
100
|
+
value: ethers.ethers.constants.Zero,
|
|
101
|
+
data: walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [transactions.sequenceTxAbiEncode(transactions$1), nonce, await encodedSignature])
|
|
102
|
+
}],
|
|
103
|
+
nonce: ethers.ethers.constants.Zero,
|
|
104
|
+
signature: '0x'
|
|
105
|
+
}
|
|
96
106
|
};
|
|
97
107
|
} else {
|
|
98
108
|
return {
|
|
99
109
|
to: walletAddress,
|
|
100
|
-
|
|
110
|
+
execute: {
|
|
111
|
+
transactions: transactions$1,
|
|
112
|
+
nonce: ethers.ethers.BigNumber.from(nonce),
|
|
113
|
+
signature: await encodedSignature
|
|
114
|
+
}
|
|
101
115
|
};
|
|
102
116
|
}
|
|
103
117
|
}
|
|
104
118
|
|
|
119
|
+
async prepareTransactions(config, context, signature, ...transactions$1) {
|
|
120
|
+
//, gasLimit?: ethers.BigNumberish }> {
|
|
121
|
+
const nonce = transactions.readSequenceNonce(...transactions$1);
|
|
122
|
+
|
|
123
|
+
if (!nonce) {
|
|
124
|
+
throw new Error('Unable to prepare transactions without a defined nonce');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const {
|
|
128
|
+
to,
|
|
129
|
+
execute
|
|
130
|
+
} = await this.prependWalletDeploy({
|
|
131
|
+
config,
|
|
132
|
+
context,
|
|
133
|
+
transactions: transactions$1,
|
|
134
|
+
nonce,
|
|
135
|
+
signature
|
|
136
|
+
});
|
|
137
|
+
const walletInterface = new utils$1.Interface(abi.walletContracts.mainModule.abi);
|
|
138
|
+
return {
|
|
139
|
+
to,
|
|
140
|
+
data: walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [transactions.sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature])
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
105
144
|
}
|
|
106
145
|
|
|
107
146
|
const DEFAULT_GAS_LIMIT = ethers.ethers.BigNumber.from(800000);
|
|
@@ -129,11 +168,10 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
129
168
|
this.fromBlockLog = opts.fromBlockLog;
|
|
130
169
|
}
|
|
131
170
|
|
|
132
|
-
async
|
|
171
|
+
async simulate(wallet, ...transactions) {
|
|
133
172
|
var _this = this;
|
|
134
173
|
|
|
135
|
-
|
|
136
|
-
const gasCosts = await Promise.all(transactions.map(async function (tx) {
|
|
174
|
+
return (await Promise.all(transactions.map(async function (tx) {
|
|
137
175
|
// Respect gasLimit request of the transaction (as long as its not 0)
|
|
138
176
|
if (tx.gasLimit && !ethers.ethers.BigNumber.from(tx.gasLimit || 0).eq(ethers.ethers.constants.Zero)) {
|
|
139
177
|
return tx.gasLimit;
|
|
@@ -145,7 +183,7 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
145
183
|
} // Fee can't be estimated for self-called if wallet hasn't been deployed
|
|
146
184
|
|
|
147
185
|
|
|
148
|
-
if (tx.to ===
|
|
186
|
+
if (tx.to === wallet && !(await _this.isWalletDeployed(wallet))) {
|
|
149
187
|
return DEFAULT_GAS_LIMIT;
|
|
150
188
|
}
|
|
151
189
|
|
|
@@ -156,16 +194,25 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
156
194
|
|
|
157
195
|
|
|
158
196
|
return _this.provider.estimateGas({
|
|
159
|
-
from:
|
|
197
|
+
from: wallet,
|
|
160
198
|
to: tx.to,
|
|
161
199
|
data: tx.data,
|
|
162
200
|
value: tx.value
|
|
163
201
|
});
|
|
202
|
+
}))).map(gasLimit => ({
|
|
203
|
+
executed: true,
|
|
204
|
+
succeeded: true,
|
|
205
|
+
gasLimit: ethers.ethers.BigNumber.from(gasLimit).toNumber(),
|
|
206
|
+
gasUsed: ethers.ethers.BigNumber.from(gasLimit).toNumber()
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async estimateGasLimits(config$1, context, ...transactions) {
|
|
211
|
+
const walletAddr = config.addressOf(config$1, context);
|
|
212
|
+
const results = await this.simulate(walletAddr, ...transactions);
|
|
213
|
+
return transactions.map((t, i) => _extends({}, t, {
|
|
214
|
+
gasLimit: results[i].gasLimit
|
|
164
215
|
}));
|
|
165
|
-
return transactions.map((t, i) => {
|
|
166
|
-
t.gasLimit = gasCosts[i];
|
|
167
|
-
return t;
|
|
168
|
-
});
|
|
169
216
|
}
|
|
170
217
|
|
|
171
218
|
async getNonce(config$1, context, space, blockTag) {
|
|
@@ -273,18 +320,26 @@ class LocalRelayer extends ProviderRelayer {
|
|
|
273
320
|
throw new Error('LocalRelayer requires the context.guestModule address');
|
|
274
321
|
}
|
|
275
322
|
|
|
276
|
-
const
|
|
323
|
+
const {
|
|
324
|
+
to,
|
|
325
|
+
execute
|
|
326
|
+
} = await this.prependWalletDeploy(signedTxs);
|
|
327
|
+
const walletInterface = new ethers.ethers.utils.Interface(abi.walletContracts.mainModule.abi);
|
|
328
|
+
const data = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [transactions.sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]); // TODO: think about computing gas limit individually, summing together and passing across
|
|
277
329
|
// NOTE: we expect that all txns have set their gasLimit ahead of time through proper estimation
|
|
278
330
|
// const gasLimit = signedTxs.transactions.reduce((sum, tx) => sum.add(tx.gasLimit), ethers.BigNumber.from(0))
|
|
279
331
|
// txRequest.gasLimit = gasLimit
|
|
280
332
|
|
|
281
|
-
return this.signer.sendTransaction(
|
|
333
|
+
return this.signer.sendTransaction({
|
|
334
|
+
to,
|
|
335
|
+
data
|
|
336
|
+
});
|
|
282
337
|
}
|
|
283
338
|
|
|
284
339
|
}
|
|
285
340
|
|
|
286
341
|
/* eslint-disable */
|
|
287
|
-
// sequence-relayer v0.4.0
|
|
342
|
+
// sequence-relayer v0.4.0 7dbfaf5c04cf28e9259ff1a9bf3274c8d73be5dd
|
|
288
343
|
// --
|
|
289
344
|
// This file has been generated by https://github.com/webrpc/webrpc using gen/typescript
|
|
290
345
|
// Do not edit by hand. Update your webrpc schema and re-generate.
|
|
@@ -293,7 +348,7 @@ const WebRPCVersion = 'v1'; // Schema version of your RIDL schema
|
|
|
293
348
|
|
|
294
349
|
const WebRPCSchemaVersion = 'v0.4.0'; // Schema hash generated from your RIDL schema
|
|
295
350
|
|
|
296
|
-
const WebRPCSchemaHash = '
|
|
351
|
+
const WebRPCSchemaHash = '7dbfaf5c04cf28e9259ff1a9bf3274c8d73be5dd'; //
|
|
297
352
|
// Types
|
|
298
353
|
//
|
|
299
354
|
|
|
@@ -425,6 +480,16 @@ class Relayer {
|
|
|
425
480
|
});
|
|
426
481
|
};
|
|
427
482
|
|
|
483
|
+
this.simulate = (args, headers) => {
|
|
484
|
+
return this.fetch(this.url('Simulate'), createHTTPRequest(args, headers)).then(res => {
|
|
485
|
+
return buildResponse(res).then(_data => {
|
|
486
|
+
return {
|
|
487
|
+
results: _data.results
|
|
488
|
+
};
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
};
|
|
492
|
+
|
|
428
493
|
this.updateMetaTxnGasLimits = (args, headers) => {
|
|
429
494
|
return this.fetch(this.url('UpdateMetaTxnGasLimits'), createHTTPRequest(args, headers)).then(res => {
|
|
430
495
|
return buildResponse(res).then(_data => {
|
|
@@ -446,6 +511,16 @@ class Relayer {
|
|
|
446
511
|
});
|
|
447
512
|
};
|
|
448
513
|
|
|
514
|
+
this.feeOptions = (args, headers) => {
|
|
515
|
+
return this.fetch(this.url('FeeOptions'), createHTTPRequest(args, headers)).then(res => {
|
|
516
|
+
return buildResponse(res).then(_data => {
|
|
517
|
+
return {
|
|
518
|
+
options: _data.options
|
|
519
|
+
};
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
};
|
|
523
|
+
|
|
449
524
|
this.getMetaTxnNetworkFeeOptions = (args, headers) => {
|
|
450
525
|
return this.fetch(this.url('GetMetaTxnNetworkFeeOptions'), createHTTPRequest(args, headers)).then(res => {
|
|
451
526
|
return buildResponse(res).then(_data => {
|
|
@@ -565,6 +640,15 @@ class RpcRelayer extends BaseRelayer {
|
|
|
565
640
|
return result;
|
|
566
641
|
}
|
|
567
642
|
|
|
643
|
+
async simulate(wallet, ...transactions$1) {
|
|
644
|
+
const coder = ethers.ethers.utils.defaultAbiCoder;
|
|
645
|
+
const encoded = coder.encode([transactions.MetaTransactionsType], [transactions.sequenceTxAbiEncode(transactions$1)]);
|
|
646
|
+
return (await this.service.simulate({
|
|
647
|
+
wallet,
|
|
648
|
+
transactions: encoded
|
|
649
|
+
})).results;
|
|
650
|
+
}
|
|
651
|
+
|
|
568
652
|
async estimateGasLimits(config$1, context, ...transactions$1) {
|
|
569
653
|
utils.logger.info(`[rpc-relayer/estimateGasLimits] estimate gas limits request ${JSON.stringify(transactions$1)}`);
|
|
570
654
|
|
|
@@ -609,23 +693,39 @@ class RpcRelayer extends BaseRelayer {
|
|
|
609
693
|
if (feeTokens.isFeeRequired) {
|
|
610
694
|
const symbols = feeTokens.tokens.map(token => token.symbol).join(', ');
|
|
611
695
|
utils.logger.info(`[rpc-relayer/gasRefundOptions] relayer fees are required, accepted tokens are ${symbols}`);
|
|
612
|
-
const
|
|
613
|
-
|
|
696
|
+
const wallet = config.addressOf(config$1, context);
|
|
697
|
+
let nonce = transactions.readSequenceNonce(...transactions$1);
|
|
698
|
+
|
|
699
|
+
if (nonce === undefined) {
|
|
700
|
+
nonce = await this.getNonce(config$1, context);
|
|
701
|
+
}
|
|
614
702
|
|
|
615
|
-
if (
|
|
616
|
-
|
|
703
|
+
if (!this.provider) {
|
|
704
|
+
utils.logger.warn(`[rpc-relayer/gasRefundOptions] provider not set, needed for stub signature`);
|
|
705
|
+
throw new Error('provider is not set');
|
|
617
706
|
}
|
|
618
707
|
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
708
|
+
const {
|
|
709
|
+
to,
|
|
710
|
+
execute
|
|
711
|
+
} = await this.prependWalletDeploy({
|
|
712
|
+
config: config$1,
|
|
713
|
+
context,
|
|
714
|
+
transactions: transactions$1,
|
|
715
|
+
nonce,
|
|
716
|
+
signature: config.buildStubSignature(this.provider, config$1)
|
|
717
|
+
});
|
|
718
|
+
const walletInterface = new ethers.ethers.utils.Interface(abi.walletContracts.mainModule.abi);
|
|
719
|
+
const data = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [transactions.sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
720
|
+
const {
|
|
721
|
+
options
|
|
722
|
+
} = await this.service.feeOptions({
|
|
723
|
+
wallet,
|
|
724
|
+
to,
|
|
725
|
+
data
|
|
626
726
|
});
|
|
627
|
-
utils.logger.info(`[rpc-relayer/gasRefundOptions] got refund options ${JSON.stringify(
|
|
628
|
-
return
|
|
727
|
+
utils.logger.info(`[rpc-relayer/gasRefundOptions] got refund options ${JSON.stringify(options)}`);
|
|
728
|
+
return options;
|
|
629
729
|
} else {
|
|
630
730
|
utils.logger.info(`[rpc-relayer/gasRefundOptions] relayer fees are not required`);
|
|
631
731
|
return [];
|
|
@@ -654,13 +754,18 @@ class RpcRelayer extends BaseRelayer {
|
|
|
654
754
|
throw new Error('provider is not set');
|
|
655
755
|
}
|
|
656
756
|
|
|
657
|
-
const
|
|
658
|
-
|
|
757
|
+
const {
|
|
758
|
+
to: contract,
|
|
759
|
+
execute
|
|
760
|
+
} = await this.prependWalletDeploy(signedTxs);
|
|
761
|
+
const walletAddress = config.addressOf(signedTxs.config, signedTxs.context);
|
|
762
|
+
const walletInterface = new ethers.ethers.utils.Interface(abi.walletContracts.mainModule.abi);
|
|
763
|
+
const input = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [transactions.sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
659
764
|
const metaTxn = await this.service.sendMetaTxn({
|
|
660
765
|
call: {
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
766
|
+
walletAddress,
|
|
767
|
+
contract,
|
|
768
|
+
input
|
|
664
769
|
}
|
|
665
770
|
});
|
|
666
771
|
utils.logger.info(`[rpc-relayer/relay] got relay result ${JSON.stringify(metaTxn)}`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ethers, providers, Signer } from 'ethers';
|
|
2
|
-
import { Provider } from '@ethersproject/providers';
|
|
3
2
|
import { walletContracts } from '@0xsequence/abi';
|
|
4
|
-
import { sequenceTxAbiEncode, readSequenceNonce, encodeNonce, computeMetaTxnHash,
|
|
5
|
-
import {
|
|
3
|
+
import { sequenceTxAbiEncode, readSequenceNonce, encodeNonce, computeMetaTxnHash, MetaTransactionsType, appendNonce, decodeNonce } from '@0xsequence/transactions';
|
|
4
|
+
import { Provider } from '@ethersproject/providers';
|
|
5
|
+
import { imageHash, addressOf, encodeSignature, buildStubSignature } from '@0xsequence/config';
|
|
6
6
|
import { Interface } from 'ethers/lib/utils';
|
|
7
7
|
import { isBigNumberish, logger } from '@0xsequence/utils';
|
|
8
8
|
import fetchPonyfill from 'fetch-ponyfill';
|
|
@@ -58,8 +58,14 @@ class BaseRelayer {
|
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
async
|
|
62
|
-
|
|
61
|
+
async prependWalletDeploy(signedTransactions) {
|
|
62
|
+
const {
|
|
63
|
+
config,
|
|
64
|
+
context,
|
|
65
|
+
transactions,
|
|
66
|
+
nonce,
|
|
67
|
+
signature
|
|
68
|
+
} = signedTransactions;
|
|
63
69
|
const walletAddress = addressOf(config, context);
|
|
64
70
|
const walletInterface = new Interface(walletContracts.mainModule.abi);
|
|
65
71
|
|
|
@@ -72,28 +78,61 @@ class BaseRelayer {
|
|
|
72
78
|
if (this.bundleCreation && !(await this.isWalletDeployed(walletAddress))) {
|
|
73
79
|
return {
|
|
74
80
|
to: context.guestModule,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
execute: {
|
|
82
|
+
transactions: [_extends({}, this.prepareWalletDeploy(config, context), {
|
|
83
|
+
delegateCall: false,
|
|
84
|
+
revertOnError: false,
|
|
85
|
+
gasLimit: this.creationGasLimit,
|
|
86
|
+
value: ethers.constants.Zero
|
|
87
|
+
}), {
|
|
88
|
+
delegateCall: false,
|
|
89
|
+
revertOnError: true,
|
|
90
|
+
gasLimit: ethers.constants.Zero,
|
|
91
|
+
to: walletAddress,
|
|
92
|
+
value: ethers.constants.Zero,
|
|
93
|
+
data: walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(transactions), nonce, await encodedSignature])
|
|
94
|
+
}],
|
|
95
|
+
nonce: ethers.constants.Zero,
|
|
96
|
+
signature: '0x'
|
|
97
|
+
}
|
|
88
98
|
};
|
|
89
99
|
} else {
|
|
90
100
|
return {
|
|
91
101
|
to: walletAddress,
|
|
92
|
-
|
|
102
|
+
execute: {
|
|
103
|
+
transactions,
|
|
104
|
+
nonce: ethers.BigNumber.from(nonce),
|
|
105
|
+
signature: await encodedSignature
|
|
106
|
+
}
|
|
93
107
|
};
|
|
94
108
|
}
|
|
95
109
|
}
|
|
96
110
|
|
|
111
|
+
async prepareTransactions(config, context, signature, ...transactions) {
|
|
112
|
+
//, gasLimit?: ethers.BigNumberish }> {
|
|
113
|
+
const nonce = readSequenceNonce(...transactions);
|
|
114
|
+
|
|
115
|
+
if (!nonce) {
|
|
116
|
+
throw new Error('Unable to prepare transactions without a defined nonce');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const {
|
|
120
|
+
to,
|
|
121
|
+
execute
|
|
122
|
+
} = await this.prependWalletDeploy({
|
|
123
|
+
config,
|
|
124
|
+
context,
|
|
125
|
+
transactions,
|
|
126
|
+
nonce,
|
|
127
|
+
signature
|
|
128
|
+
});
|
|
129
|
+
const walletInterface = new Interface(walletContracts.mainModule.abi);
|
|
130
|
+
return {
|
|
131
|
+
to,
|
|
132
|
+
data: walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature])
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
97
136
|
}
|
|
98
137
|
|
|
99
138
|
const DEFAULT_GAS_LIMIT = ethers.BigNumber.from(800000);
|
|
@@ -121,11 +160,10 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
121
160
|
this.fromBlockLog = opts.fromBlockLog;
|
|
122
161
|
}
|
|
123
162
|
|
|
124
|
-
async
|
|
163
|
+
async simulate(wallet, ...transactions) {
|
|
125
164
|
var _this = this;
|
|
126
165
|
|
|
127
|
-
|
|
128
|
-
const gasCosts = await Promise.all(transactions.map(async function (tx) {
|
|
166
|
+
return (await Promise.all(transactions.map(async function (tx) {
|
|
129
167
|
// Respect gasLimit request of the transaction (as long as its not 0)
|
|
130
168
|
if (tx.gasLimit && !ethers.BigNumber.from(tx.gasLimit || 0).eq(ethers.constants.Zero)) {
|
|
131
169
|
return tx.gasLimit;
|
|
@@ -137,7 +175,7 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
137
175
|
} // Fee can't be estimated for self-called if wallet hasn't been deployed
|
|
138
176
|
|
|
139
177
|
|
|
140
|
-
if (tx.to ===
|
|
178
|
+
if (tx.to === wallet && !(await _this.isWalletDeployed(wallet))) {
|
|
141
179
|
return DEFAULT_GAS_LIMIT;
|
|
142
180
|
}
|
|
143
181
|
|
|
@@ -148,16 +186,25 @@ class ProviderRelayer extends BaseRelayer {
|
|
|
148
186
|
|
|
149
187
|
|
|
150
188
|
return _this.provider.estimateGas({
|
|
151
|
-
from:
|
|
189
|
+
from: wallet,
|
|
152
190
|
to: tx.to,
|
|
153
191
|
data: tx.data,
|
|
154
192
|
value: tx.value
|
|
155
193
|
});
|
|
194
|
+
}))).map(gasLimit => ({
|
|
195
|
+
executed: true,
|
|
196
|
+
succeeded: true,
|
|
197
|
+
gasLimit: ethers.BigNumber.from(gasLimit).toNumber(),
|
|
198
|
+
gasUsed: ethers.BigNumber.from(gasLimit).toNumber()
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async estimateGasLimits(config, context, ...transactions) {
|
|
203
|
+
const walletAddr = addressOf(config, context);
|
|
204
|
+
const results = await this.simulate(walletAddr, ...transactions);
|
|
205
|
+
return transactions.map((t, i) => _extends({}, t, {
|
|
206
|
+
gasLimit: results[i].gasLimit
|
|
156
207
|
}));
|
|
157
|
-
return transactions.map((t, i) => {
|
|
158
|
-
t.gasLimit = gasCosts[i];
|
|
159
|
-
return t;
|
|
160
|
-
});
|
|
161
208
|
}
|
|
162
209
|
|
|
163
210
|
async getNonce(config, context, space, blockTag) {
|
|
@@ -265,18 +312,26 @@ class LocalRelayer extends ProviderRelayer {
|
|
|
265
312
|
throw new Error('LocalRelayer requires the context.guestModule address');
|
|
266
313
|
}
|
|
267
314
|
|
|
268
|
-
const
|
|
315
|
+
const {
|
|
316
|
+
to,
|
|
317
|
+
execute
|
|
318
|
+
} = await this.prependWalletDeploy(signedTxs);
|
|
319
|
+
const walletInterface = new ethers.utils.Interface(walletContracts.mainModule.abi);
|
|
320
|
+
const data = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]); // TODO: think about computing gas limit individually, summing together and passing across
|
|
269
321
|
// NOTE: we expect that all txns have set their gasLimit ahead of time through proper estimation
|
|
270
322
|
// const gasLimit = signedTxs.transactions.reduce((sum, tx) => sum.add(tx.gasLimit), ethers.BigNumber.from(0))
|
|
271
323
|
// txRequest.gasLimit = gasLimit
|
|
272
324
|
|
|
273
|
-
return this.signer.sendTransaction(
|
|
325
|
+
return this.signer.sendTransaction({
|
|
326
|
+
to,
|
|
327
|
+
data
|
|
328
|
+
});
|
|
274
329
|
}
|
|
275
330
|
|
|
276
331
|
}
|
|
277
332
|
|
|
278
333
|
/* eslint-disable */
|
|
279
|
-
// sequence-relayer v0.4.0
|
|
334
|
+
// sequence-relayer v0.4.0 7dbfaf5c04cf28e9259ff1a9bf3274c8d73be5dd
|
|
280
335
|
// --
|
|
281
336
|
// This file has been generated by https://github.com/webrpc/webrpc using gen/typescript
|
|
282
337
|
// Do not edit by hand. Update your webrpc schema and re-generate.
|
|
@@ -285,7 +340,7 @@ const WebRPCVersion = 'v1'; // Schema version of your RIDL schema
|
|
|
285
340
|
|
|
286
341
|
const WebRPCSchemaVersion = 'v0.4.0'; // Schema hash generated from your RIDL schema
|
|
287
342
|
|
|
288
|
-
const WebRPCSchemaHash = '
|
|
343
|
+
const WebRPCSchemaHash = '7dbfaf5c04cf28e9259ff1a9bf3274c8d73be5dd'; //
|
|
289
344
|
// Types
|
|
290
345
|
//
|
|
291
346
|
|
|
@@ -417,6 +472,16 @@ class Relayer {
|
|
|
417
472
|
});
|
|
418
473
|
};
|
|
419
474
|
|
|
475
|
+
this.simulate = (args, headers) => {
|
|
476
|
+
return this.fetch(this.url('Simulate'), createHTTPRequest(args, headers)).then(res => {
|
|
477
|
+
return buildResponse(res).then(_data => {
|
|
478
|
+
return {
|
|
479
|
+
results: _data.results
|
|
480
|
+
};
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
};
|
|
484
|
+
|
|
420
485
|
this.updateMetaTxnGasLimits = (args, headers) => {
|
|
421
486
|
return this.fetch(this.url('UpdateMetaTxnGasLimits'), createHTTPRequest(args, headers)).then(res => {
|
|
422
487
|
return buildResponse(res).then(_data => {
|
|
@@ -438,6 +503,16 @@ class Relayer {
|
|
|
438
503
|
});
|
|
439
504
|
};
|
|
440
505
|
|
|
506
|
+
this.feeOptions = (args, headers) => {
|
|
507
|
+
return this.fetch(this.url('FeeOptions'), createHTTPRequest(args, headers)).then(res => {
|
|
508
|
+
return buildResponse(res).then(_data => {
|
|
509
|
+
return {
|
|
510
|
+
options: _data.options
|
|
511
|
+
};
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
};
|
|
515
|
+
|
|
441
516
|
this.getMetaTxnNetworkFeeOptions = (args, headers) => {
|
|
442
517
|
return this.fetch(this.url('GetMetaTxnNetworkFeeOptions'), createHTTPRequest(args, headers)).then(res => {
|
|
443
518
|
return buildResponse(res).then(_data => {
|
|
@@ -557,6 +632,15 @@ class RpcRelayer extends BaseRelayer {
|
|
|
557
632
|
return result;
|
|
558
633
|
}
|
|
559
634
|
|
|
635
|
+
async simulate(wallet, ...transactions) {
|
|
636
|
+
const coder = ethers.utils.defaultAbiCoder;
|
|
637
|
+
const encoded = coder.encode([MetaTransactionsType], [sequenceTxAbiEncode(transactions)]);
|
|
638
|
+
return (await this.service.simulate({
|
|
639
|
+
wallet,
|
|
640
|
+
transactions: encoded
|
|
641
|
+
})).results;
|
|
642
|
+
}
|
|
643
|
+
|
|
560
644
|
async estimateGasLimits(config, context, ...transactions) {
|
|
561
645
|
logger.info(`[rpc-relayer/estimateGasLimits] estimate gas limits request ${JSON.stringify(transactions)}`);
|
|
562
646
|
|
|
@@ -601,23 +685,39 @@ class RpcRelayer extends BaseRelayer {
|
|
|
601
685
|
if (feeTokens.isFeeRequired) {
|
|
602
686
|
const symbols = feeTokens.tokens.map(token => token.symbol).join(', ');
|
|
603
687
|
logger.info(`[rpc-relayer/gasRefundOptions] relayer fees are required, accepted tokens are ${symbols}`);
|
|
604
|
-
const
|
|
605
|
-
|
|
688
|
+
const wallet = addressOf(config, context);
|
|
689
|
+
let nonce = readSequenceNonce(...transactions);
|
|
690
|
+
|
|
691
|
+
if (nonce === undefined) {
|
|
692
|
+
nonce = await this.getNonce(config, context);
|
|
693
|
+
}
|
|
606
694
|
|
|
607
|
-
if (
|
|
608
|
-
|
|
695
|
+
if (!this.provider) {
|
|
696
|
+
logger.warn(`[rpc-relayer/gasRefundOptions] provider not set, needed for stub signature`);
|
|
697
|
+
throw new Error('provider is not set');
|
|
609
698
|
}
|
|
610
699
|
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
700
|
+
const {
|
|
701
|
+
to,
|
|
702
|
+
execute
|
|
703
|
+
} = await this.prependWalletDeploy({
|
|
704
|
+
config,
|
|
705
|
+
context,
|
|
706
|
+
transactions,
|
|
707
|
+
nonce,
|
|
708
|
+
signature: buildStubSignature(this.provider, config)
|
|
709
|
+
});
|
|
710
|
+
const walletInterface = new ethers.utils.Interface(walletContracts.mainModule.abi);
|
|
711
|
+
const data = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
712
|
+
const {
|
|
713
|
+
options
|
|
714
|
+
} = await this.service.feeOptions({
|
|
715
|
+
wallet,
|
|
716
|
+
to,
|
|
717
|
+
data
|
|
618
718
|
});
|
|
619
|
-
logger.info(`[rpc-relayer/gasRefundOptions] got refund options ${JSON.stringify(
|
|
620
|
-
return
|
|
719
|
+
logger.info(`[rpc-relayer/gasRefundOptions] got refund options ${JSON.stringify(options)}`);
|
|
720
|
+
return options;
|
|
621
721
|
} else {
|
|
622
722
|
logger.info(`[rpc-relayer/gasRefundOptions] relayer fees are not required`);
|
|
623
723
|
return [];
|
|
@@ -646,13 +746,18 @@ class RpcRelayer extends BaseRelayer {
|
|
|
646
746
|
throw new Error('provider is not set');
|
|
647
747
|
}
|
|
648
748
|
|
|
649
|
-
const
|
|
650
|
-
|
|
749
|
+
const {
|
|
750
|
+
to: contract,
|
|
751
|
+
execute
|
|
752
|
+
} = await this.prependWalletDeploy(signedTxs);
|
|
753
|
+
const walletAddress = addressOf(signedTxs.config, signedTxs.context);
|
|
754
|
+
const walletInterface = new ethers.utils.Interface(walletContracts.mainModule.abi);
|
|
755
|
+
const input = walletInterface.encodeFunctionData(walletInterface.getFunction('execute'), [sequenceTxAbiEncode(execute.transactions), execute.nonce, execute.signature]);
|
|
651
756
|
const metaTxn = await this.service.sendMetaTxn({
|
|
652
757
|
call: {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
758
|
+
walletAddress,
|
|
759
|
+
contract,
|
|
760
|
+
input
|
|
656
761
|
}
|
|
657
762
|
});
|
|
658
763
|
logger.info(`[rpc-relayer/relay] got relay result ${JSON.stringify(metaTxn)}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ethers, providers } from "ethers";
|
|
2
2
|
import { WalletContext } from '@0xsequence/network';
|
|
3
3
|
import { WalletConfig, DecodedSignature } from '@0xsequence/config';
|
|
4
|
-
import { Transaction } from '@0xsequence/transactions';
|
|
4
|
+
import { SignedTransactions, Transaction } from '@0xsequence/transactions';
|
|
5
5
|
import { Optionals } from '@0xsequence/utils';
|
|
6
6
|
import { Provider } from "@ethersproject/providers";
|
|
7
7
|
export interface BaseRelayerOptions {
|
|
@@ -21,6 +21,14 @@ export declare class BaseRelayer {
|
|
|
21
21
|
to: string;
|
|
22
22
|
data: string;
|
|
23
23
|
};
|
|
24
|
+
prependWalletDeploy(signedTransactions: Pick<SignedTransactions, 'config' | 'context' | 'transactions' | 'nonce' | 'signature'>): Promise<{
|
|
25
|
+
to: string;
|
|
26
|
+
execute: {
|
|
27
|
+
transactions: Transaction[];
|
|
28
|
+
nonce: ethers.BigNumber;
|
|
29
|
+
signature: string;
|
|
30
|
+
};
|
|
31
|
+
}>;
|
|
24
32
|
prepareTransactions(config: WalletConfig, context: WalletContext, signature: string | Promise<string> | DecodedSignature | Promise<DecodedSignature>, ...transactions: Transaction[]): Promise<{
|
|
25
33
|
to: string;
|
|
26
34
|
data: string;
|