@0xsequence/relayer 3.0.0-beta.8 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/.turbo/turbo-lint.log +4 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/CHANGELOG.md +134 -0
  5. package/dist/preconditions/codec.d.ts.map +1 -1
  6. package/dist/preconditions/codec.js +55 -45
  7. package/dist/relayer/relayer.d.ts +2 -2
  8. package/dist/relayer/relayer.d.ts.map +1 -1
  9. package/dist/relayer/relayer.js +3 -1
  10. package/dist/relayer/rpc-relayer/index.d.ts +3 -3
  11. package/dist/relayer/rpc-relayer/index.d.ts.map +1 -1
  12. package/dist/relayer/rpc-relayer/index.js +26 -25
  13. package/dist/relayer/standard/eip6963.d.ts +2 -2
  14. package/dist/relayer/standard/eip6963.d.ts.map +1 -1
  15. package/dist/relayer/standard/eip6963.js +3 -3
  16. package/dist/relayer/standard/local.d.ts +2 -3
  17. package/dist/relayer/standard/local.d.ts.map +1 -1
  18. package/dist/relayer/standard/local.js +14 -30
  19. package/dist/relayer/standard/pk-relayer.d.ts +3 -3
  20. package/dist/relayer/standard/pk-relayer.d.ts.map +1 -1
  21. package/dist/relayer/standard/pk-relayer.js +3 -3
  22. package/dist/relayer/standard/sequence.d.ts +3 -3
  23. package/dist/relayer/standard/sequence.d.ts.map +1 -1
  24. package/dist/relayer/standard/sequence.js +2 -3
  25. package/eslint.config.js +4 -0
  26. package/package.json +9 -7
  27. package/src/preconditions/codec.ts +63 -39
  28. package/src/relayer/relayer.ts +4 -1
  29. package/src/relayer/rpc-relayer/index.ts +50 -33
  30. package/src/relayer/standard/eip6963.ts +4 -3
  31. package/src/relayer/standard/local.ts +37 -44
  32. package/src/relayer/standard/pk-relayer.ts +4 -3
  33. package/src/relayer/standard/sequence.ts +3 -3
  34. package/test/preconditions/codec.test.ts +11 -11
  35. package/test/preconditions/preconditions.test.ts +97 -138
  36. package/test/preconditions/selectors.test.ts +76 -254
  37. package/test/preconditions/types.test.ts +6 -6
  38. package/test/relayer/relayer.test.ts +4 -4
@@ -1,6 +1,5 @@
1
- import { Constants, Payload } from '@0xsequence/wallet-primitives';
2
- import { AbiFunction, Bytes, TransactionReceipt } from 'ox';
3
- import { decodePrecondition } from '../../preconditions/index.js';
1
+ import { AbiFunction, TransactionReceipt } from 'ox';
2
+ import { decodePrecondition, } from '../../preconditions/index.js';
4
3
  import { erc20BalanceOf, erc20Allowance, erc721OwnerOf, erc721GetApproved, erc1155BalanceOf, erc1155IsApprovedForAll, } from './abi.js';
5
4
  export class LocalRelayer {
6
5
  provider;
@@ -29,21 +28,9 @@ export class LocalRelayer {
29
28
  isFeeRequired: false,
30
29
  });
31
30
  }
32
- feeOptions(wallet, chainId, calls) {
31
+ feeOptions(_wallet, _chainId, _to, _calls) {
33
32
  return Promise.resolve({ options: [] });
34
33
  }
35
- decodeCalls(data) {
36
- const executeSelector = AbiFunction.getSelector(Constants.EXECUTE);
37
- let packedPayload;
38
- if (data.startsWith(executeSelector)) {
39
- const decode = AbiFunction.decodeData(Constants.EXECUTE, data);
40
- packedPayload = decode[0];
41
- }
42
- else {
43
- packedPayload = data;
44
- }
45
- return Payload.decode(Bytes.fromHex(packedPayload));
46
- }
47
34
  async relay(to, data, chainId, quote, preconditions, checkInterval = 5000) {
48
35
  // Helper function to check all preconditions
49
36
  const checkAllPreconditions = async () => {
@@ -125,7 +112,7 @@ export class LocalRelayer {
125
112
  switch (decoded.type()) {
126
113
  case 'native-balance': {
127
114
  const native = decoded;
128
- const balance = await this.provider.getBalance(native.address.toString());
115
+ const balance = await this.provider.getBalance(native.address);
129
116
  if (native.min !== undefined && balance < native.min) {
130
117
  return false;
131
118
  }
@@ -136,9 +123,9 @@ export class LocalRelayer {
136
123
  }
137
124
  case 'erc20-balance': {
138
125
  const erc20 = decoded;
139
- const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address.toString()]);
126
+ const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address]);
140
127
  const result = await this.provider.call({
141
- to: erc20.token.toString(),
128
+ to: erc20.token,
142
129
  data,
143
130
  });
144
131
  const balance = BigInt(result);
@@ -152,9 +139,9 @@ export class LocalRelayer {
152
139
  }
153
140
  case 'erc20-approval': {
154
141
  const erc20 = decoded;
155
- const data = AbiFunction.encodeData(erc20Allowance, [erc20.address.toString(), erc20.operator.toString()]);
142
+ const data = AbiFunction.encodeData(erc20Allowance, [erc20.address, erc20.operator]);
156
143
  const result = await this.provider.call({
157
- to: erc20.token.toString(),
144
+ to: erc20.token,
158
145
  data,
159
146
  });
160
147
  const allowance = BigInt(result);
@@ -164,7 +151,7 @@ export class LocalRelayer {
164
151
  const erc721 = decoded;
165
152
  const data = AbiFunction.encodeData(erc721OwnerOf, [erc721.tokenId]);
166
153
  const result = await this.provider.call({
167
- to: erc721.token.toString(),
154
+ to: erc721.token,
168
155
  data,
169
156
  });
170
157
  const owner = '0x' + result.slice(26);
@@ -175,7 +162,7 @@ export class LocalRelayer {
175
162
  const erc721 = decoded;
176
163
  const data = AbiFunction.encodeData(erc721GetApproved, [erc721.tokenId]);
177
164
  const result = await this.provider.call({
178
- to: erc721.token.toString(),
165
+ to: erc721.token,
179
166
  data,
180
167
  });
181
168
  const approved = '0x' + result.slice(26);
@@ -183,9 +170,9 @@ export class LocalRelayer {
183
170
  }
184
171
  case 'erc1155-balance': {
185
172
  const erc1155 = decoded;
186
- const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address.toString(), erc1155.tokenId]);
173
+ const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address, erc1155.tokenId]);
187
174
  const result = await this.provider.call({
188
- to: erc1155.token.toString(),
175
+ to: erc1155.token,
189
176
  data,
190
177
  });
191
178
  const balance = BigInt(result);
@@ -199,12 +186,9 @@ export class LocalRelayer {
199
186
  }
200
187
  case 'erc1155-approval': {
201
188
  const erc1155 = decoded;
202
- const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [
203
- erc1155.address.toString(),
204
- erc1155.operator.toString(),
205
- ]);
189
+ const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [erc1155.address, erc1155.operator]);
206
190
  const result = await this.provider.call({
207
- to: erc1155.token.toString(),
191
+ to: erc1155.token,
208
192
  data,
209
193
  });
210
194
  return BigInt(result) === 1n;
@@ -4,7 +4,7 @@ import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js';
4
4
  import { FeeToken } from '../rpc-relayer/relayer.gen.js';
5
5
  export declare class PkRelayer implements Relayer {
6
6
  private readonly provider;
7
- readonly kind: 'relayer';
7
+ readonly kind = "relayer";
8
8
  readonly type = "pk";
9
9
  readonly id = "pk";
10
10
  private readonly relayer;
@@ -15,7 +15,7 @@ export declare class PkRelayer implements Relayer {
15
15
  tokens?: FeeToken[];
16
16
  paymentAddress?: Address.Address;
17
17
  }>;
18
- feeOptions(wallet: Address.Address, chainId: number, calls: Payload.Call[]): Promise<{
18
+ feeOptions(wallet: Address.Address, chainId: number, to: Address.Address, calls: Payload.Call[]): Promise<{
19
19
  options: FeeOption[];
20
20
  quote?: FeeQuote;
21
21
  }>;
@@ -23,6 +23,6 @@ export declare class PkRelayer implements Relayer {
23
23
  opHash: Hex.Hex;
24
24
  }>;
25
25
  status(opHash: Hex.Hex, chainId: number): Promise<OperationStatus>;
26
- checkPrecondition(precondition: Precondition.Precondition): Promise<boolean>;
26
+ checkPrecondition(_precondition: Precondition.Precondition): Promise<boolean>;
27
27
  }
28
28
  //# sourceMappingURL=pk-relayer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pk-relayer.d.ts","sourceRoot":"","sources":["../../../src/relayer/standard/pk-relayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAA6D,MAAM,IAAI,CAAA;AAEtG,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAExD,qBAAa,SAAU,YAAW,OAAO;IAQrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP3B,SAAgB,IAAI,EAAE,SAAS,CAAY;IAC3C,SAAgB,IAAI,QAAO;IAC3B,SAAgB,EAAE,QAAO;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;gBAGpC,UAAU,EAAE,GAAG,CAAC,GAAG,EACF,QAAQ,EAAE,QAAQ,CAAC,QAAQ;IA0FxC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK9E,SAAS,IAAI,OAAO,CAAC;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC,OAAO,CAAA;KAAE,CAAC;IAIvG,UAAU,CACR,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GACpB,OAAO,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAC;IAIhD,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAA;KAAE,CAAC;IAQ5G,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAI5D,iBAAiB,CAAC,YAAY,EAAE,YAAY,CAAC,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;CAInF"}
1
+ {"version":3,"file":"pk-relayer.d.ts","sourceRoot":"","sources":["../../../src/relayer/standard/pk-relayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAA6D,MAAM,IAAI,CAAA;AAEtG,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAExD,qBAAa,SAAU,YAAW,OAAO;IAQrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP3B,SAAgB,IAAI,aAAY;IAChC,SAAgB,IAAI,QAAO;IAC3B,SAAgB,EAAE,QAAO;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;gBAGpC,UAAU,EAAE,GAAG,CAAC,GAAG,EACF,QAAQ,EAAE,QAAQ,CAAC,QAAQ;IA0FxC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK9E,SAAS,IAAI,OAAO,CAAC;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC,OAAO,CAAA;KAAE,CAAC;IAIvG,UAAU,CACR,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,OAAO,CAAC,OAAO,EACnB,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GACpB,OAAO,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAC;IAIhD,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAA;KAAE,CAAC;IAQ5G,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAI5D,iBAAiB,CAAC,aAAa,EAAE,YAAY,CAAC,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;CAIpF"}
@@ -92,8 +92,8 @@ export class PkRelayer {
92
92
  feeTokens() {
93
93
  return this.relayer.feeTokens();
94
94
  }
95
- feeOptions(wallet, chainId, calls) {
96
- return this.relayer.feeOptions(wallet, chainId, calls);
95
+ feeOptions(wallet, chainId, to, calls) {
96
+ return this.relayer.feeOptions(wallet, chainId, to, calls);
97
97
  }
98
98
  async relay(to, data, chainId, _) {
99
99
  const providerChainId = Number(await this.provider.request({ method: 'eth_chainId' }));
@@ -105,7 +105,7 @@ export class PkRelayer {
105
105
  status(opHash, chainId) {
106
106
  return this.relayer.status(opHash, chainId);
107
107
  }
108
- async checkPrecondition(precondition) {
108
+ async checkPrecondition(_precondition) {
109
109
  // TODO: Implement precondition check
110
110
  return true;
111
111
  }
@@ -3,7 +3,7 @@ import { Payload } from '@0xsequence/wallet-primitives';
3
3
  import { Address, Hex } from 'ox';
4
4
  import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js';
5
5
  export declare class SequenceRelayer implements Relayer {
6
- readonly kind: 'relayer';
6
+ readonly kind = "relayer";
7
7
  readonly type = "sequence";
8
8
  readonly id = "sequence";
9
9
  private readonly service;
@@ -14,11 +14,11 @@ export declare class SequenceRelayer implements Relayer {
14
14
  tokens?: FeeToken[];
15
15
  paymentAddress?: Address.Address;
16
16
  }>;
17
- feeOptions(wallet: Address.Address, _chainId: number, calls: Payload.Call[]): Promise<{
17
+ feeOptions(wallet: Address.Address, _chainId: number, to: Address.Address, calls: Payload.Call[]): Promise<{
18
18
  options: FeeOption[];
19
19
  quote?: FeeQuote;
20
20
  }>;
21
- checkPrecondition(precondition: TransactionPrecondition): Promise<boolean>;
21
+ checkPrecondition(_precondition: TransactionPrecondition): Promise<boolean>;
22
22
  relay(to: Address.Address, data: Hex.Hex, _chainId: number, quote?: FeeQuote): Promise<{
23
23
  opHash: Hex.Hex;
24
24
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../../src/relayer/standard/sequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,uBAAuB,EAAsB,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AACnH,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AACvD,OAAO,EAAe,OAAO,EAAS,GAAG,EAAE,MAAM,IAAI,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,qBAAa,eAAgB,YAAW,OAAO;IAC7C,SAAgB,IAAI,EAAE,SAAS,CAAY;IAC3C,SAAgB,IAAI,cAAa;IACjC,QAAQ,CAAC,EAAE,cAAa;IAExB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,MAAM;IAIlB,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzE,SAAS,IAAI,OAAO,CAAC;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC,OAAO,CAAA;KAAE,CAAC;IAgBvG,UAAU,CACd,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GACpB,OAAO,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAC;IAehD,iBAAiB,CAAC,YAAY,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1E,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAA;KAAE,CAAC;IAW3G,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;CAuC1E"}
1
+ {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../../src/relayer/standard/sequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,uBAAuB,EAAsB,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AACnH,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AACvD,OAAO,EAAe,OAAO,EAAS,GAAG,EAAE,MAAM,IAAI,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,qBAAa,eAAgB,YAAW,OAAO;IAC7C,SAAgB,IAAI,aAAY;IAChC,SAAgB,IAAI,cAAa;IACjC,QAAQ,CAAC,EAAE,cAAa;IAExB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,MAAM;IAIlB,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzE,SAAS,IAAI,OAAO,CAAC;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC,OAAO,CAAA;KAAE,CAAC;IAgBvG,UAAU,CACd,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,OAAO,CAAC,OAAO,EACnB,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GACpB,OAAO,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAC;IAchD,iBAAiB,CAAC,aAAa,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3E,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAA;KAAE,CAAC;IAW3G,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;CAuC1E"}
@@ -27,8 +27,7 @@ export class SequenceRelayer {
27
27
  isFeeRequired,
28
28
  };
29
29
  }
30
- async feeOptions(wallet, _chainId, calls) {
31
- const to = wallet; // TODO: this might be the guest module
30
+ async feeOptions(wallet, _chainId, to, calls) {
32
31
  const execute = AbiFunction.from('function execute(bytes calldata _payload, bytes calldata _signature)');
33
32
  const payload = Payload.encode({ type: 'call', space: 0n, nonce: 0n, calls }, to);
34
33
  const signature = '0x0001'; // TODO: use a stub signature
@@ -39,7 +38,7 @@ export class SequenceRelayer {
39
38
  quote: quote ? { _tag: 'FeeQuote', _quote: quote } : undefined,
40
39
  };
41
40
  }
42
- async checkPrecondition(precondition) {
41
+ async checkPrecondition(_precondition) {
43
42
  // TODO: implement
44
43
  return false;
45
44
  }
@@ -0,0 +1,4 @@
1
+ import { config as baseConfig } from "@repo/eslint-config/base"
2
+
3
+ /** @type {import("eslint").Linter.Config} */
4
+ export default baseConfig
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@0xsequence/relayer",
3
- "version": "3.0.0-beta.8",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "description": "relayer sub-package for Sequence",
9
9
  "repository": "https://github.com/0xsequence/sequence.js/tree/master/packages/services/relayer",
10
- "author": "Sequence Platforms Inc.",
10
+ "author": "Sequence Platforms ULC",
11
11
  "license": "Apache-2.0",
12
12
  "exports": {
13
13
  ".": {
@@ -16,16 +16,17 @@
16
16
  }
17
17
  },
18
18
  "devDependencies": {
19
- "@types/node": "^25.0.2",
19
+ "@types/node": "^25.3.0",
20
20
  "typescript": "^5.9.3",
21
- "vitest": "^4.0.15",
22
- "@repo/typescript-config": "^0.0.1-beta.1"
21
+ "vitest": "^4.0.18",
22
+ "@repo/typescript-config": "^0.0.1",
23
+ "@repo/eslint-config": "^0.0.1"
23
24
  },
24
25
  "dependencies": {
25
26
  "mipd": "^0.0.7",
26
27
  "ox": "^0.9.17",
27
28
  "viem": "^2.40.3",
28
- "@0xsequence/wallet-primitives": "^3.0.0-beta.8"
29
+ "@0xsequence/wallet-primitives": "^3.0.0"
29
30
  },
30
31
  "scripts": {
31
32
  "build": "tsc",
@@ -35,6 +36,7 @@
35
36
  "old-test:file": "NODE_OPTIONS='--import tsx' mocha --timeout 60000",
36
37
  "old-test:concurrently": "concurrently -k --success first 'pnpm start:hardhat > /dev/null' ",
37
38
  "start:hardhat": "pnpm hardhat node --port 9547",
38
- "typecheck": "tsc --noEmit"
39
+ "typecheck": "tsc --noEmit",
40
+ "lint": "eslint . --max-warnings 0"
39
41
  }
40
42
  }
@@ -36,6 +36,11 @@ export function decodePrecondition(p: TransactionPrecondition): Precondition | u
36
36
  return undefined
37
37
  }
38
38
 
39
+ if (typeof p.minAmount !== 'bigint') {
40
+ console.warn(`Failed to decode precondition: minAmount must be a bigint`)
41
+ return undefined
42
+ }
43
+
39
44
  let precondition: Precondition | undefined
40
45
 
41
46
  try {
@@ -118,73 +123,92 @@ export function decodePrecondition(p: TransactionPrecondition): Precondition | u
118
123
  }
119
124
 
120
125
  export function encodePrecondition(p: Precondition): string {
121
- const data: any = {}
122
-
123
126
  switch (p.type()) {
124
127
  case 'native-balance': {
125
128
  const native = p as NativeBalancePrecondition
126
- data.address = native.address.toString()
127
- if (native.min !== undefined) data.min = native.min.toString()
128
- if (native.max !== undefined) data.max = native.max.toString()
129
- break
129
+ const data = {
130
+ address: native.address.toString(),
131
+ ...(native.min !== undefined && { min: native.min.toString() }),
132
+ ...(native.max !== undefined && { max: native.max.toString() }),
133
+ }
134
+
135
+ return JSON.stringify(data)
130
136
  }
131
137
 
132
138
  case 'erc20-balance': {
133
139
  const erc20 = p as Erc20BalancePrecondition
134
- data.address = erc20.address.toString()
135
- data.token = erc20.token.toString()
136
- if (erc20.min !== undefined) data.min = erc20.min.toString()
137
- if (erc20.max !== undefined) data.max = erc20.max.toString()
138
- break
140
+ const data = {
141
+ address: erc20.address.toString(),
142
+ token: erc20.token.toString(),
143
+ ...(erc20.min !== undefined && { min: erc20.min.toString() }),
144
+ ...(erc20.max !== undefined && { max: erc20.max.toString() }),
145
+ }
146
+
147
+ return JSON.stringify(data)
139
148
  }
140
149
 
141
150
  case 'erc20-approval': {
142
151
  const erc20 = p as Erc20ApprovalPrecondition
143
- data.address = erc20.address.toString()
144
- data.token = erc20.token.toString()
145
- data.operator = erc20.operator.toString()
146
- data.min = erc20.min.toString()
147
- break
152
+ const data = {
153
+ address: erc20.address.toString(),
154
+ token: erc20.token.toString(),
155
+ operator: erc20.operator.toString(),
156
+ min: erc20.min.toString(),
157
+ }
158
+
159
+ return JSON.stringify(data)
148
160
  }
149
161
 
150
162
  case 'erc721-ownership': {
151
163
  const erc721 = p as Erc721OwnershipPrecondition
152
- data.address = erc721.address.toString()
153
- data.token = erc721.token.toString()
154
- data.tokenId = erc721.tokenId.toString()
155
- if (erc721.owned !== undefined) data.owned = erc721.owned
156
- break
164
+ const data = {
165
+ address: erc721.address.toString(),
166
+ token: erc721.token.toString(),
167
+ tokenId: erc721.tokenId.toString(),
168
+ ...(erc721.owned !== undefined && { owned: erc721.owned }),
169
+ }
170
+
171
+ return JSON.stringify(data)
157
172
  }
158
173
 
159
174
  case 'erc721-approval': {
160
175
  const erc721 = p as Erc721ApprovalPrecondition
161
- data.address = erc721.address.toString()
162
- data.token = erc721.token.toString()
163
- data.tokenId = erc721.tokenId.toString()
164
- data.operator = erc721.operator.toString()
165
- break
176
+ const data = {
177
+ address: erc721.address.toString(),
178
+ token: erc721.token.toString(),
179
+ tokenId: erc721.tokenId.toString(),
180
+ operator: erc721.operator.toString(),
181
+ }
182
+
183
+ return JSON.stringify(data)
166
184
  }
167
185
 
168
186
  case 'erc1155-balance': {
169
187
  const erc1155 = p as Erc1155BalancePrecondition
170
- data.address = erc1155.address.toString()
171
- data.token = erc1155.token.toString()
172
- data.tokenId = erc1155.tokenId.toString()
173
- if (erc1155.min !== undefined) data.min = erc1155.min.toString()
174
- if (erc1155.max !== undefined) data.max = erc1155.max.toString()
175
- break
188
+ const data = {
189
+ address: erc1155.address.toString(),
190
+ token: erc1155.token.toString(),
191
+ tokenId: erc1155.tokenId.toString(),
192
+ ...(erc1155.min !== undefined && { min: erc1155.min.toString() }),
193
+ ...(erc1155.max !== undefined && { max: erc1155.max.toString() }),
194
+ }
195
+
196
+ return JSON.stringify(data)
176
197
  }
177
198
 
178
199
  case 'erc1155-approval': {
179
200
  const erc1155 = p as Erc1155ApprovalPrecondition
180
- data.address = erc1155.address.toString()
181
- data.token = erc1155.token.toString()
182
- data.tokenId = erc1155.tokenId.toString()
183
- data.operator = erc1155.operator.toString()
184
- data.min = erc1155.min.toString()
185
- break
201
+ const data = {
202
+ address: erc1155.address.toString(),
203
+ token: erc1155.token.toString(),
204
+ tokenId: erc1155.tokenId.toString(),
205
+ operator: erc1155.operator.toString(),
206
+ min: erc1155.min.toString(),
207
+ }
208
+
209
+ return JSON.stringify(data)
186
210
  }
187
211
  }
188
212
 
189
- return JSON.stringify(data)
213
+ return JSON.stringify({})
190
214
  }
@@ -16,6 +16,7 @@ export interface Relayer {
16
16
  feeOptions(
17
17
  wallet: Address.Address,
18
18
  chainId: number,
19
+ to: Address.Address,
19
20
  calls: Payload.Call[],
20
21
  ): Promise<{ options: FeeOption[]; quote?: FeeQuote }>
21
22
 
@@ -26,8 +27,10 @@ export interface Relayer {
26
27
  checkPrecondition(precondition: Precondition.Precondition): Promise<boolean>
27
28
  }
28
29
 
29
- export function isRelayer(relayer: any): relayer is Relayer {
30
+ export function isRelayer(relayer: unknown): relayer is Relayer {
30
31
  return (
32
+ typeof relayer === 'object' &&
33
+ relayer !== null &&
31
34
  'isAvailable' in relayer &&
32
35
  'feeOptions' in relayer &&
33
36
  'relay' in relayer &&
@@ -7,10 +7,19 @@ import {
7
7
  TransactionPrecondition,
8
8
  ETHTxnStatus,
9
9
  } from './relayer.gen.js'
10
- import { Address, Hex, Bytes, AbiFunction } from 'ox'
10
+ import { Address, Hex, AbiFunction } from 'ox'
11
11
  import { Constants, Payload, Network } from '@0xsequence/wallet-primitives'
12
12
  import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js'
13
- import { decodePrecondition } from '../../preconditions/index.js'
13
+ import {
14
+ decodePrecondition,
15
+ Erc1155ApprovalPrecondition,
16
+ Erc1155BalancePrecondition,
17
+ Erc20ApprovalPrecondition,
18
+ Erc20BalancePrecondition,
19
+ Erc721ApprovalPrecondition,
20
+ Erc721OwnershipPrecondition,
21
+ NativeBalancePrecondition,
22
+ } from '../../preconditions/index.js'
14
23
  import {
15
24
  erc20BalanceOf,
16
25
  erc20Allowance,
@@ -49,12 +58,14 @@ const networkToChain = (network: Network.Network): Chain => {
49
58
  },
50
59
  }
51
60
  : undefined,
52
- contracts: network.ensAddress
53
- ? {
54
- ensUniversalResolver: {
55
- address: network.ensAddress as `0x${string}`,
61
+ contracts: network.contracts
62
+ ? Object.entries(network.contracts).reduce(
63
+ (acc, [name, address]) => {
64
+ acc[name] = { address }
65
+ return acc
56
66
  },
57
- }
67
+ {} as Record<string, { address: Address.Address }>,
68
+ )
58
69
  : undefined,
59
70
  } as Chain
60
71
  }
@@ -67,7 +78,9 @@ export const getChain = (chainId: number): Chain => {
67
78
  }
68
79
 
69
80
  // Fall back to viem's built-in chains
70
- const viemChain = Object.values(chains).find((c: any) => typeof c === 'object' && 'id' in c && c.id === chainId)
81
+ const viemChain = Object.values(chains).find(
82
+ (c: unknown) => typeof c === 'object' && c !== null && 'id' in c && c.id === chainId,
83
+ )
71
84
  if (viemChain) {
72
85
  return viemChain as Chain
73
86
  }
@@ -76,7 +89,7 @@ export const getChain = (chainId: number): Chain => {
76
89
  }
77
90
 
78
91
  export class RpcRelayer implements Relayer {
79
- public readonly kind: 'relayer' = 'relayer'
92
+ public readonly kind = 'relayer'
80
93
  public readonly type = 'rpc'
81
94
  public readonly id: string
82
95
  public readonly chainId: number
@@ -134,17 +147,24 @@ export class RpcRelayer implements Relayer {
134
147
  async feeOptions(
135
148
  wallet: Address.Address,
136
149
  chainId: number,
150
+ to: Address.Address,
137
151
  calls: Payload.Call[],
138
152
  ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
153
+ // IMPORTANT:
154
+ // The relayer FeeOptions endpoint simulates `eth_call(to, data)`.
155
+ // wallet-webapp-v3 requests FeeOptions with `to = wallet` and `data = Payload.encode(calls, self=wallet)`.
156
+ // This works for undeployed wallets and avoids guest-module simulation pitfalls.
139
157
  const callsStruct: Payload.Calls = { type: 'call', space: 0n, nonce: 0n, calls: calls }
140
- const data = Payload.encode(callsStruct)
158
+
159
+ const feeOptionsTo = wallet
160
+ const data = Payload.encode(callsStruct, wallet)
141
161
 
142
162
  try {
143
163
  const result = await this.client.feeOptions(
144
164
  {
145
- wallet: wallet,
146
- to: wallet,
147
- data: Bytes.toHex(data),
165
+ wallet,
166
+ to: feeOptionsTo,
167
+ data: Hex.fromBytes(data),
148
168
  },
149
169
  { ...(this.projectAccessKey ? { 'X-Access-Key': this.projectAccessKey } : undefined) },
150
170
  )
@@ -230,7 +250,7 @@ export class RpcRelayer implements Relayer {
230
250
  return { opHash: `0x${result.txnHash}` }
231
251
  }
232
252
 
233
- async status(opHash: Hex.Hex, chainId: number): Promise<OperationStatus> {
253
+ async status(opHash: Hex.Hex, _chainId: number): Promise<OperationStatus> {
234
254
  try {
235
255
  const cleanedOpHash = opHash.startsWith('0x') ? opHash.substring(2) : opHash
236
256
  const result = await this.client.getMetaTxnReceipt({ metaTxID: cleanedOpHash })
@@ -282,9 +302,9 @@ export class RpcRelayer implements Relayer {
282
302
 
283
303
  switch (decoded.type()) {
284
304
  case 'native-balance': {
285
- const native = decoded as any
305
+ const native = decoded as NativeBalancePrecondition
286
306
  try {
287
- const balance = await this.provider.getBalance({ address: native.address.toString() as `0x${string}` })
307
+ const balance = await this.provider.getBalance({ address: native.address })
288
308
  const minWei = native.min !== undefined ? BigInt(native.min) : undefined
289
309
  const maxWei = native.max !== undefined ? BigInt(native.max) : undefined
290
310
 
@@ -307,9 +327,9 @@ export class RpcRelayer implements Relayer {
307
327
  }
308
328
 
309
329
  case 'erc20-balance': {
310
- const erc20 = decoded as any
330
+ const erc20 = decoded as Erc20BalancePrecondition
311
331
  try {
312
- const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address.toString()])
332
+ const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address])
313
333
  const result = await this.provider.call({
314
334
  to: erc20.token.toString() as `0x${string}`,
315
335
  data: data as `0x${string}`,
@@ -336,9 +356,9 @@ export class RpcRelayer implements Relayer {
336
356
  }
337
357
 
338
358
  case 'erc20-approval': {
339
- const erc20 = decoded as any
359
+ const erc20 = decoded as Erc20ApprovalPrecondition
340
360
  try {
341
- const data = AbiFunction.encodeData(erc20Allowance, [erc20.address.toString(), erc20.operator.toString()])
361
+ const data = AbiFunction.encodeData(erc20Allowance, [erc20.address, erc20.operator])
342
362
  const result = await this.provider.call({
343
363
  to: erc20.token.toString() as `0x${string}`,
344
364
  data: data as `0x${string}`,
@@ -353,12 +373,12 @@ export class RpcRelayer implements Relayer {
353
373
  }
354
374
 
355
375
  case 'erc721-ownership': {
356
- const erc721 = decoded as any
376
+ const erc721 = decoded as Erc721OwnershipPrecondition
357
377
  try {
358
378
  const data = AbiFunction.encodeData(erc721OwnerOf, [erc721.tokenId])
359
379
  const result = await this.provider.call({
360
- to: erc721.token.toString() as `0x${string}`,
361
- data: data as `0x${string}`,
380
+ to: erc721.token,
381
+ data: data,
362
382
  })
363
383
  const resultHex = result.toString() as `0x${string}`
364
384
  const owner = resultHex.slice(-40)
@@ -372,7 +392,7 @@ export class RpcRelayer implements Relayer {
372
392
  }
373
393
 
374
394
  case 'erc721-approval': {
375
- const erc721 = decoded as any
395
+ const erc721 = decoded as Erc721ApprovalPrecondition
376
396
  try {
377
397
  const data = AbiFunction.encodeData(erc721GetApproved, [erc721.tokenId])
378
398
  const result = await this.provider.call({
@@ -389,9 +409,9 @@ export class RpcRelayer implements Relayer {
389
409
  }
390
410
 
391
411
  case 'erc1155-balance': {
392
- const erc1155 = decoded as any
412
+ const erc1155 = decoded as Erc1155BalancePrecondition
393
413
  try {
394
- const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address.toString(), erc1155.tokenId])
414
+ const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address, erc1155.tokenId])
395
415
  const result = await this.provider.call({
396
416
  to: erc1155.token.toString() as `0x${string}`,
397
417
  data: data as `0x${string}`,
@@ -418,15 +438,12 @@ export class RpcRelayer implements Relayer {
418
438
  }
419
439
 
420
440
  case 'erc1155-approval': {
421
- const erc1155 = decoded as any
441
+ const erc1155 = decoded as Erc1155ApprovalPrecondition
422
442
  try {
423
- const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [
424
- erc1155.address.toString(),
425
- erc1155.operator.toString(),
426
- ])
443
+ const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [erc1155.address, erc1155.operator])
427
444
  const result = await this.provider.call({
428
- to: erc1155.token.toString() as `0x${string}`,
429
- data: data as `0x${string}`,
445
+ to: erc1155.token,
446
+ data: data,
430
447
  })
431
448
  return BigInt(result.toString()) === 1n
432
449
  } catch (error) {
@@ -6,7 +6,7 @@ import { Payload } from '@0xsequence/wallet-primitives'
6
6
  import { FeeToken, TransactionPrecondition } from '../rpc-relayer/relayer.gen.js'
7
7
 
8
8
  export class EIP6963Relayer implements Relayer {
9
- public readonly kind: 'relayer' = 'relayer'
9
+ public readonly kind = 'relayer'
10
10
  public readonly type = 'eip6963'
11
11
  public readonly id: string
12
12
  public readonly info: EIP6963ProviderInfo
@@ -30,9 +30,10 @@ export class EIP6963Relayer implements Relayer {
30
30
  feeOptions(
31
31
  wallet: Address.Address,
32
32
  chainId: number,
33
+ to: Address.Address,
33
34
  calls: Payload.Call[],
34
35
  ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
35
- return this.relayer.feeOptions(wallet, chainId, calls)
36
+ return this.relayer.feeOptions(wallet, chainId, to, calls)
36
37
  }
37
38
 
38
39
  async relay(to: Address.Address, data: Hex.Hex, chainId: number, _?: FeeQuote): Promise<{ opHash: Hex.Hex }> {
@@ -58,7 +59,7 @@ export function getEIP6963Store() {
58
59
  return store
59
60
  }
60
61
 
61
- let relayers: Map<string, EIP6963Relayer> = new Map()
62
+ const relayers: Map<string, EIP6963Relayer> = new Map()
62
63
 
63
64
  export function getRelayers(): EIP6963Relayer[] {
64
65
  const store = getEIP6963Store()