@0xsequence/relayer 2.3.35 → 3.0.0-beta.2

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.
Files changed (84) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/CHANGELOG.md +3862 -0
  3. package/LICENSE +0 -17
  4. package/README.md +1 -2
  5. package/dist/index.d.ts +4 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +3 -0
  8. package/dist/preconditions/codec.d.ts +12 -0
  9. package/dist/preconditions/codec.d.ts.map +1 -0
  10. package/dist/preconditions/codec.js +125 -0
  11. package/dist/preconditions/index.d.ts +4 -0
  12. package/dist/preconditions/index.d.ts.map +1 -0
  13. package/dist/preconditions/index.js +3 -0
  14. package/dist/preconditions/selectors.d.ts +7 -0
  15. package/dist/preconditions/selectors.d.ts.map +1 -0
  16. package/dist/preconditions/selectors.js +27 -0
  17. package/dist/preconditions/types.d.ts +70 -0
  18. package/dist/preconditions/types.d.ts.map +1 -0
  19. package/dist/preconditions/types.js +203 -0
  20. package/dist/relayer/index.d.ts +45 -0
  21. package/dist/relayer/index.d.ts.map +1 -0
  22. package/dist/relayer/index.js +3 -0
  23. package/dist/relayer/relayer.d.ts +26 -0
  24. package/dist/relayer/relayer.d.ts.map +1 -0
  25. package/dist/relayer/relayer.js +7 -0
  26. package/dist/relayer/rpc-relayer/index.d.ts +38 -0
  27. package/dist/relayer/rpc-relayer/index.d.ts.map +1 -0
  28. package/dist/relayer/rpc-relayer/index.js +375 -0
  29. package/dist/{declarations/src → relayer}/rpc-relayer/relayer.gen.d.ts +218 -178
  30. package/dist/relayer/rpc-relayer/relayer.gen.d.ts.map +1 -0
  31. package/dist/relayer/rpc-relayer/relayer.gen.js +1246 -0
  32. package/dist/relayer/standard/abi.d.ts +73 -0
  33. package/dist/relayer/standard/abi.d.ts.map +1 -0
  34. package/dist/relayer/standard/abi.js +10 -0
  35. package/dist/relayer/standard/eip6963.d.ts +31 -0
  36. package/dist/relayer/standard/eip6963.d.ts.map +1 -0
  37. package/dist/relayer/standard/eip6963.js +51 -0
  38. package/dist/relayer/standard/index.d.ts +5 -0
  39. package/dist/relayer/standard/index.d.ts.map +1 -0
  40. package/dist/relayer/standard/index.js +4 -0
  41. package/dist/relayer/standard/local.d.ts +60 -0
  42. package/dist/relayer/standard/local.d.ts.map +1 -0
  43. package/dist/relayer/standard/local.js +285 -0
  44. package/dist/relayer/standard/pk-relayer.d.ts +28 -0
  45. package/dist/relayer/standard/pk-relayer.d.ts.map +1 -0
  46. package/dist/relayer/standard/pk-relayer.js +112 -0
  47. package/dist/relayer/standard/sequence.d.ts +27 -0
  48. package/dist/relayer/standard/sequence.d.ts.map +1 -0
  49. package/dist/relayer/standard/sequence.js +84 -0
  50. package/package.json +28 -25
  51. package/src/index.ts +3 -111
  52. package/src/preconditions/codec.ts +190 -0
  53. package/src/preconditions/index.ts +3 -0
  54. package/src/preconditions/selectors.ts +38 -0
  55. package/src/preconditions/types.ts +201 -0
  56. package/src/relayer/index.ts +60 -0
  57. package/src/relayer/relayer.ts +37 -0
  58. package/src/relayer/rpc-relayer/index.ts +449 -0
  59. package/src/relayer/rpc-relayer/relayer.gen.ts +2268 -0
  60. package/src/relayer/standard/abi.ts +13 -0
  61. package/src/relayer/standard/eip6963.ts +74 -0
  62. package/src/relayer/standard/index.ts +4 -0
  63. package/src/relayer/standard/local.ts +353 -0
  64. package/src/relayer/standard/pk-relayer.ts +138 -0
  65. package/src/relayer/standard/sequence.ts +110 -0
  66. package/test/preconditions/codec.test.ts +531 -0
  67. package/test/preconditions/preconditions.test.ts +283 -0
  68. package/test/preconditions/selectors.test.ts +415 -0
  69. package/test/preconditions/types.test.ts +443 -0
  70. package/test/relayer/relayer.test.ts +355 -0
  71. package/tsconfig.json +10 -0
  72. package/dist/0xsequence-relayer.cjs.d.ts +0 -2
  73. package/dist/0xsequence-relayer.cjs.dev.js +0 -1626
  74. package/dist/0xsequence-relayer.cjs.js +0 -7
  75. package/dist/0xsequence-relayer.cjs.prod.js +0 -1626
  76. package/dist/0xsequence-relayer.esm.js +0 -1613
  77. package/dist/declarations/src/index.d.ts +0 -42
  78. package/dist/declarations/src/local-relayer.d.ts +0 -35
  79. package/dist/declarations/src/provider-relayer.d.ts +0 -47
  80. package/dist/declarations/src/rpc-relayer/index.d.ts +0 -72
  81. package/src/local-relayer.ts +0 -125
  82. package/src/provider-relayer.ts +0 -284
  83. package/src/rpc-relayer/index.ts +0 -380
  84. package/src/rpc-relayer/relayer.gen.ts +0 -1900
@@ -1,380 +0,0 @@
1
- import { ethers } from 'ethers'
2
- import { FeeOption, FeeQuote, Relayer, SimulateResult } from '..'
3
- import * as proto from './relayer.gen'
4
- import { commons } from '@0xsequence/core'
5
- import { bigintReplacer, getFetchRequest, logger, toHexString } from '@0xsequence/utils'
6
-
7
- export { proto }
8
-
9
- const FINAL_STATUSES = [
10
- proto.ETHTxnStatus.DROPPED,
11
- proto.ETHTxnStatus.SUCCEEDED,
12
- proto.ETHTxnStatus.PARTIALLY_FAILED,
13
- proto.ETHTxnStatus.FAILED
14
- ]
15
-
16
- const FAILED_STATUSES = [proto.ETHTxnStatus.DROPPED, proto.ETHTxnStatus.PARTIALLY_FAILED, proto.ETHTxnStatus.FAILED]
17
-
18
- export interface RpcRelayerOptions {
19
- provider: ethers.AbstractProvider | { url: string }
20
- url: string
21
- projectAccessKey?: string
22
- jwtAuth?: string
23
- }
24
-
25
- export function isRpcRelayerOptions(obj: any): obj is RpcRelayerOptions {
26
- return obj.url !== undefined && typeof obj.url === 'string' && obj.provider !== undefined && isAbstractProvider(obj.provider)
27
- }
28
-
29
- // TODO: rename to SequenceRelayer
30
- export class RpcRelayer implements Relayer {
31
- private readonly service: proto.Relayer
32
- public readonly provider: ethers.Provider
33
-
34
- constructor(public options: RpcRelayerOptions) {
35
- this.service = new proto.Relayer(options.url, this._fetch)
36
-
37
- if (isAbstractProvider(options.provider)) {
38
- this.provider = options.provider
39
- } else {
40
- const { jwtAuth, projectAccessKey } = this.options
41
- const fetchRequest = getFetchRequest(options.provider.url, projectAccessKey, jwtAuth)
42
- this.provider = new ethers.JsonRpcProvider(fetchRequest, undefined, { staticNetwork: true })
43
- }
44
- }
45
-
46
- _fetch = (input: RequestInfo, init?: RequestInit): Promise<Response> => {
47
- // automatically include jwt and access key auth header to requests
48
- // if its been set on the api client
49
- const headers: { [key: string]: any } = {}
50
-
51
- const { jwtAuth, projectAccessKey } = this.options
52
-
53
- if (jwtAuth && jwtAuth.length > 0) {
54
- headers['Authorization'] = `BEARER ${jwtAuth}`
55
- }
56
-
57
- if (projectAccessKey && projectAccessKey.length > 0) {
58
- headers['X-Access-Key'] = projectAccessKey
59
- }
60
-
61
- // before the request is made
62
- init!.headers = { ...headers, ...init!.headers }
63
-
64
- return fetch(input, init)
65
- }
66
-
67
- async waitReceipt(
68
- metaTxnId: string | commons.transaction.SignedTransactionBundle,
69
- delay: number = 1000,
70
- maxFails: number = 5,
71
- isCancelled?: () => boolean
72
- ): Promise<proto.GetMetaTxnReceiptReturn> {
73
- if (typeof metaTxnId !== 'string') {
74
- metaTxnId = commons.transaction.intendedTransactionID(metaTxnId)
75
- }
76
-
77
- logger.info(`[rpc-relayer/waitReceipt] waiting for ${metaTxnId}`)
78
-
79
- let fails = 0
80
-
81
- while (isCancelled === undefined || !isCancelled()) {
82
- try {
83
- const { receipt } = await this.service.getMetaTxnReceipt({ metaTxID: metaTxnId })
84
-
85
- if (
86
- receipt &&
87
- receipt.txnReceipt &&
88
- receipt.txnReceipt !== 'null' &&
89
- FINAL_STATUSES.includes(receipt.status as proto.ETHTxnStatus)
90
- ) {
91
- return { receipt }
92
- }
93
- } catch (e) {
94
- fails++
95
-
96
- if (fails === maxFails) {
97
- throw e
98
- }
99
- }
100
-
101
- if (isCancelled === undefined || !isCancelled()) {
102
- await new Promise(resolve => setTimeout(resolve, delay))
103
- }
104
- }
105
-
106
- throw new Error(`Cancelled waiting for transaction receipt ${metaTxnId}`)
107
- }
108
-
109
- async simulate(wallet: string, ...transactions: commons.transaction.Transaction[]): Promise<SimulateResult[]> {
110
- const coder = ethers.AbiCoder.defaultAbiCoder()
111
- const encoded = coder.encode(
112
- [commons.transaction.MetaTransactionsType],
113
- [commons.transaction.sequenceTxAbiEncode(transactions)]
114
- )
115
- return (await this.service.simulate({ wallet, transactions: encoded })).results
116
- }
117
-
118
- async getFeeOptions(
119
- address: string,
120
- ...transactions: commons.transaction.Transaction[]
121
- ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
122
- // NOTE/TODO: for a given `service` the feeTokens will not change between execution, so we should memoize this value
123
- // for a short-period of time, perhaps for 1 day or in memory. Perhaps one day we can make this happen automatically
124
- // with http cache response for this endpoint and service-worker.. lots of approaches
125
- const feeTokens = await this.service.feeTokens()
126
-
127
- if (feeTokens.isFeeRequired) {
128
- const symbols = feeTokens.tokens.map(token => token.symbol).join(', ')
129
- logger.info(`[rpc-relayer/getFeeOptions] relayer fees are required, accepted tokens are ${symbols}`)
130
-
131
- const nonce = await this.getNonce(address)
132
-
133
- if (!this.provider) {
134
- logger.warn(`[rpc-relayer/getFeeOptions] provider not set, needed for stub signature`)
135
- throw new Error('provider is not set')
136
- }
137
-
138
- const { options, quote } = await this.service.feeOptions({
139
- wallet: address,
140
- to: address,
141
- data: commons.transaction.encodeBundleExecData({
142
- entrypoint: address,
143
- transactions,
144
- nonce
145
- })
146
- })
147
-
148
- logger.info(`[rpc-relayer/getFeeOptions] got refund options ${JSON.stringify(options, bigintReplacer)}`)
149
- return { options, quote: { _tag: 'FeeQuote', _quote: quote } }
150
- } else {
151
- logger.info(`[rpc-relayer/getFeeOptions] relayer fees are not required`)
152
- return { options: [] }
153
- }
154
- }
155
-
156
- async getFeeOptionsRaw(
157
- entrypoint: string,
158
- data: ethers.BytesLike,
159
- options?: {
160
- simulate?: boolean
161
- projectAccessKey?: string
162
- }
163
- ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
164
- const { options: feeOptions, quote } = await this.service.feeOptions(
165
- {
166
- wallet: entrypoint,
167
- to: entrypoint,
168
- data: ethers.hexlify(data),
169
- simulate: options?.simulate
170
- },
171
- { ...(options?.projectAccessKey ? { 'X-Access-Key': options.projectAccessKey } : undefined) }
172
- )
173
-
174
- return { options: feeOptions, quote: { _tag: 'FeeQuote', _quote: quote } }
175
- }
176
-
177
- async gasRefundOptions(address: string, ...transactions: commons.transaction.Transaction[]): Promise<FeeOption[]> {
178
- const { options } = await this.getFeeOptions(address, ...transactions)
179
- return options
180
- }
181
-
182
- async getNonce(address: string, space?: ethers.BigNumberish): Promise<ethers.BigNumberish> {
183
- logger.info(`[rpc-relayer/getNonce] get nonce for wallet ${address} space: ${space}`)
184
- const encodedNonce = space !== undefined ? toHexString(BigInt(space)) : undefined
185
- const resp = await this.service.getMetaTxnNonce({ walletContractAddress: address, space: encodedNonce })
186
- const nonce = BigInt(resp.nonce)
187
- const [decodedSpace, decodedNonce] = commons.transaction.decodeNonce(nonce)
188
- logger.info(`[rpc-relayer/getNonce] got next nonce for wallet ${address} ${decodedNonce} space: ${decodedSpace}`)
189
- return nonce
190
- }
191
-
192
- async relay(
193
- signedTxs: commons.transaction.IntendedTransactionBundle,
194
- quote?: FeeQuote,
195
- waitForReceipt: boolean = true,
196
- projectAccessKey?: string
197
- ): Promise<commons.transaction.TransactionResponse<RelayerTxReceipt>> {
198
- logger.info(
199
- `[rpc-relayer/relay] relaying signed meta-transactions ${JSON.stringify(signedTxs, bigintReplacer)} with quote ${JSON.stringify(quote, bigintReplacer)}`
200
- )
201
-
202
- let typecheckedQuote: string | undefined
203
- if (quote !== undefined) {
204
- if (typeof quote._quote === 'string') {
205
- typecheckedQuote = quote._quote
206
- } else {
207
- logger.warn('[rpc-relayer/relay] ignoring invalid fee quote')
208
- }
209
- }
210
-
211
- if (!this.provider) {
212
- logger.warn(`[rpc-relayer/relay] provider not set, failed relay`)
213
- throw new Error('provider is not set')
214
- }
215
-
216
- const data = commons.transaction.encodeBundleExecData(signedTxs)
217
- const metaTxn = await this.service.sendMetaTxn(
218
- {
219
- call: {
220
- walletAddress: signedTxs.intent.wallet,
221
- contract: signedTxs.entrypoint,
222
- input: data
223
- },
224
- quote: typecheckedQuote
225
- },
226
- { ...(projectAccessKey ? { 'X-Access-Key': projectAccessKey } : undefined) }
227
- )
228
-
229
- logger.info(`[rpc-relayer/relay] got relay result ${JSON.stringify(metaTxn, bigintReplacer)}`)
230
-
231
- if (waitForReceipt) {
232
- return this.wait(signedTxs.intent.id)
233
- } else {
234
- const response = {
235
- hash: signedTxs.intent.id,
236
- confirmations: 0,
237
- from: signedTxs.intent.wallet,
238
- wait: (_confirmations?: number): Promise<ethers.TransactionReceipt | null> => Promise.reject(new Error('impossible'))
239
- }
240
-
241
- const wait = async (confirmations?: number): Promise<ethers.TransactionReceipt | null> => {
242
- if (!this.provider) {
243
- throw new Error('cannot wait for receipt, relayer has no provider set')
244
- }
245
-
246
- const waitResponse = await this.wait(signedTxs.intent.id)
247
- const transactionHash = waitResponse.receipt?.transactionHash
248
-
249
- if (!transactionHash) {
250
- throw new Error('cannot wait for receipt, unknown native transaction hash')
251
- }
252
-
253
- Object.assign(response, waitResponse)
254
-
255
- return this.provider.waitForTransaction(transactionHash, confirmations)
256
- }
257
-
258
- response.wait = wait
259
-
260
- // NOTE: we just ignore these errors which come from the private fields
261
- // of ethers-v6 .. but, we should probably rework this instead..
262
- // @ts-ignore
263
- return response as commons.transaction.TransactionResponse
264
- }
265
- }
266
-
267
- async wait(
268
- metaTxnId: string | commons.transaction.SignedTransactionBundle,
269
- timeout?: number,
270
- delay: number = 1000,
271
- maxFails: number = 5
272
- ): Promise<commons.transaction.TransactionResponse<RelayerTxReceipt>> {
273
- let timedOut = false
274
-
275
- const { receipt } = await (timeout !== undefined
276
- ? Promise.race([
277
- this.waitReceipt(metaTxnId, delay, maxFails, () => timedOut),
278
- new Promise<proto.GetMetaTxnReceiptReturn>((_, reject) =>
279
- setTimeout(() => {
280
- timedOut = true
281
- reject(`Timeout waiting for transaction receipt ${metaTxnId}`)
282
- }, timeout)
283
- )
284
- ])
285
- : this.waitReceipt(metaTxnId, delay, maxFails))
286
-
287
- if (!receipt.txnReceipt || FAILED_STATUSES.includes(receipt.status as proto.ETHTxnStatus)) {
288
- throw new MetaTransactionResponseException(receipt)
289
- }
290
-
291
- const txReceipt = JSON.parse(receipt.txnReceipt) as RelayerTxReceipt
292
-
293
- // NOTE: we just ignore these errors which come from the private fields
294
- // of ethers-v6 .. but, we should probably rework this instead..
295
- // @ts-ignore
296
- return {
297
- blockHash: txReceipt.blockHash,
298
- blockNumber: Number(txReceipt.blockNumber),
299
- confirmations: 1,
300
- from: typeof metaTxnId === 'string' ? undefined : metaTxnId.intent.wallet,
301
- hash: txReceipt.transactionHash,
302
- raw: receipt.txnReceipt,
303
- receipt: txReceipt, // extended type which is Sequence-specific. Contains the decoded metaTxReceipt
304
- wait: async (confirmations?: number) => this.provider!.waitForTransaction(txReceipt.transactionHash, confirmations)
305
- } as commons.transaction.TransactionResponse
306
- }
307
-
308
- async getMetaTransactions(
309
- projectId: number,
310
- page?: proto.Page
311
- ): Promise<{
312
- page: proto.Page
313
- transactions: proto.MetaTxnLog[]
314
- }> {
315
- return this.service.getMetaTransactions({ projectId, page })
316
- }
317
-
318
- async getTransactionCost(
319
- projectId: number,
320
- from: string,
321
- to: string
322
- ): Promise<{
323
- cost: number
324
- }> {
325
- return this.service.getTransactionCost({ projectId, from, to })
326
- }
327
-
328
- async listGasSponsors(args: proto.ListGasSponsorsArgs): Promise<proto.ListGasSponsorsReturn> {
329
- return this.service.listGasSponsors(args)
330
- }
331
-
332
- async addGasSponsor(args: proto.AddGasSponsorArgs): Promise<proto.AddGasSponsorReturn> {
333
- return this.service.addGasSponsor(args)
334
- }
335
-
336
- async updateGasSponsor(args: proto.UpdateGasSponsorArgs): Promise<proto.UpdateGasSponsorReturn> {
337
- return this.service.updateGasSponsor(args)
338
- }
339
-
340
- async removeGasSponsor(args: proto.RemoveGasSponsorArgs): Promise<proto.RemoveGasSponsorReturn> {
341
- return this.service.removeGasSponsor(args)
342
- }
343
- }
344
-
345
- class MetaTransactionResponseException {
346
- constructor(public receipt: proto.MetaTxnReceipt) {}
347
- }
348
-
349
- export type RelayerTxReceipt = {
350
- blockHash: string
351
- blockNumber: string
352
- contractAddress: string
353
- cumulativeGasUsed: string
354
- gasUsed: string
355
- logs: {
356
- address: string
357
- blockHash: string
358
- blockNumber: string
359
- data: string
360
- logIndex: string
361
- removed: boolean
362
- topics: string[]
363
- transactionHash: string
364
- transactionIndex: string
365
- }[]
366
- logsBloom: string
367
- root: string
368
- status: string
369
- transactionHash: string
370
- transactionIndex: string
371
- }
372
-
373
- function isAbstractProvider(provider: any): provider is ethers.AbstractProvider {
374
- return (
375
- provider &&
376
- typeof provider === 'object' &&
377
- typeof provider.getNetwork === 'function' &&
378
- typeof provider.getBlockNumber === 'function'
379
- )
380
- }