@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,9 +1,18 @@
1
- import { Constants, Payload } from '@0xsequence/wallet-primitives'
1
+ import { Payload } from '@0xsequence/wallet-primitives'
2
2
  import { EIP1193Provider } from 'mipd'
3
- import { AbiFunction, Address, Bytes, Hex, TransactionReceipt } from 'ox'
3
+ import { AbiFunction, Address, Hex, TransactionReceipt } from 'ox'
4
4
  import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js'
5
5
  import { FeeToken, TransactionPrecondition } from '../rpc-relayer/relayer.gen.js'
6
- import { decodePrecondition } from '../../preconditions/index.js'
6
+ import {
7
+ decodePrecondition,
8
+ Erc1155ApprovalPrecondition,
9
+ Erc1155BalancePrecondition,
10
+ Erc20ApprovalPrecondition,
11
+ Erc20BalancePrecondition,
12
+ Erc721ApprovalPrecondition,
13
+ Erc721OwnershipPrecondition,
14
+ NativeBalancePrecondition,
15
+ } from '../../preconditions/index.js'
7
16
  import {
8
17
  erc20BalanceOf,
9
18
  erc20Allowance,
@@ -23,7 +32,7 @@ export interface GenericProvider {
23
32
  }
24
33
 
25
34
  export class LocalRelayer implements Relayer {
26
- public readonly kind: 'relayer' = 'relayer'
35
+ public readonly kind = 'relayer'
27
36
  public readonly type = 'local'
28
37
  public readonly id = 'local'
29
38
 
@@ -34,7 +43,7 @@ export class LocalRelayer implements Relayer {
34
43
  }
35
44
 
36
45
  static createFromWindow(window: Window): LocalRelayer | undefined {
37
- const eth = (window as any).ethereum
46
+ const eth = (window as { ethereum?: EIP1193Provider }).ethereum
38
47
  if (!eth) {
39
48
  console.warn('Window.ethereum not found, skipping local relayer')
40
49
  return undefined
@@ -54,27 +63,14 @@ export class LocalRelayer implements Relayer {
54
63
  }
55
64
 
56
65
  feeOptions(
57
- wallet: Address.Address,
58
- chainId: number,
59
- calls: Payload.Call[],
66
+ _wallet: Address.Address,
67
+ _chainId: number,
68
+ _to: Address.Address,
69
+ _calls: Payload.Call[],
60
70
  ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
61
71
  return Promise.resolve({ options: [] })
62
72
  }
63
73
 
64
- private decodeCalls(data: Hex.Hex): Payload.Calls {
65
- const executeSelector = AbiFunction.getSelector(Constants.EXECUTE)
66
-
67
- let packedPayload
68
- if (data.startsWith(executeSelector)) {
69
- const decode = AbiFunction.decodeData(Constants.EXECUTE, data)
70
- packedPayload = decode[0]
71
- } else {
72
- packedPayload = data
73
- }
74
-
75
- return Payload.decode(Bytes.fromHex(packedPayload))
76
- }
77
-
78
74
  async relay(
79
75
  to: Address.Address,
80
76
  data: Hex.Hex,
@@ -177,8 +173,8 @@ export class LocalRelayer implements Relayer {
177
173
 
178
174
  switch (decoded.type()) {
179
175
  case 'native-balance': {
180
- const native = decoded as any
181
- const balance = await this.provider.getBalance(native.address.toString())
176
+ const native = decoded as NativeBalancePrecondition
177
+ const balance = await this.provider.getBalance(native.address)
182
178
  if (native.min !== undefined && balance < native.min) {
183
179
  return false
184
180
  }
@@ -189,10 +185,10 @@ export class LocalRelayer implements Relayer {
189
185
  }
190
186
 
191
187
  case 'erc20-balance': {
192
- const erc20 = decoded as any
193
- const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address.toString()])
188
+ const erc20 = decoded as Erc20BalancePrecondition
189
+ const data = AbiFunction.encodeData(erc20BalanceOf, [erc20.address])
194
190
  const result = await this.provider.call({
195
- to: erc20.token.toString(),
191
+ to: erc20.token,
196
192
  data,
197
193
  })
198
194
  const balance = BigInt(result)
@@ -206,10 +202,10 @@ export class LocalRelayer implements Relayer {
206
202
  }
207
203
 
208
204
  case 'erc20-approval': {
209
- const erc20 = decoded as any
210
- const data = AbiFunction.encodeData(erc20Allowance, [erc20.address.toString(), erc20.operator.toString()])
205
+ const erc20 = decoded as Erc20ApprovalPrecondition
206
+ const data = AbiFunction.encodeData(erc20Allowance, [erc20.address, erc20.operator])
211
207
  const result = await this.provider.call({
212
- to: erc20.token.toString(),
208
+ to: erc20.token,
213
209
  data,
214
210
  })
215
211
  const allowance = BigInt(result)
@@ -217,10 +213,10 @@ export class LocalRelayer implements Relayer {
217
213
  }
218
214
 
219
215
  case 'erc721-ownership': {
220
- const erc721 = decoded as any
216
+ const erc721 = decoded as Erc721OwnershipPrecondition
221
217
  const data = AbiFunction.encodeData(erc721OwnerOf, [erc721.tokenId])
222
218
  const result = await this.provider.call({
223
- to: erc721.token.toString(),
219
+ to: erc721.token,
224
220
  data,
225
221
  })
226
222
  const owner = '0x' + result.slice(26)
@@ -229,10 +225,10 @@ export class LocalRelayer implements Relayer {
229
225
  }
230
226
 
231
227
  case 'erc721-approval': {
232
- const erc721 = decoded as any
228
+ const erc721 = decoded as Erc721ApprovalPrecondition
233
229
  const data = AbiFunction.encodeData(erc721GetApproved, [erc721.tokenId])
234
230
  const result = await this.provider.call({
235
- to: erc721.token.toString(),
231
+ to: erc721.token,
236
232
  data,
237
233
  })
238
234
  const approved = '0x' + result.slice(26)
@@ -240,10 +236,10 @@ export class LocalRelayer implements Relayer {
240
236
  }
241
237
 
242
238
  case 'erc1155-balance': {
243
- const erc1155 = decoded as any
244
- const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address.toString(), erc1155.tokenId])
239
+ const erc1155 = decoded as Erc1155BalancePrecondition
240
+ const data = AbiFunction.encodeData(erc1155BalanceOf, [erc1155.address, erc1155.tokenId])
245
241
  const result = await this.provider.call({
246
- to: erc1155.token.toString(),
242
+ to: erc1155.token,
247
243
  data,
248
244
  })
249
245
  const balance = BigInt(result)
@@ -257,13 +253,10 @@ export class LocalRelayer implements Relayer {
257
253
  }
258
254
 
259
255
  case 'erc1155-approval': {
260
- const erc1155 = decoded as any
261
- const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [
262
- erc1155.address.toString(),
263
- erc1155.operator.toString(),
264
- ])
256
+ const erc1155 = decoded as Erc1155ApprovalPrecondition
257
+ const data = AbiFunction.encodeData(erc1155IsApprovedForAll, [erc1155.address, erc1155.operator])
265
258
  const result = await this.provider.call({
266
- to: erc1155.token.toString(),
259
+ to: erc1155.token,
267
260
  data,
268
261
  })
269
262
  return BigInt(result) === 1n
@@ -340,7 +333,7 @@ export class EIP1193ProviderAdapter implements GenericProvider {
340
333
  const rpcReceipt = await this.provider.request({ method: 'eth_getTransactionReceipt', params: [txHash] })
341
334
 
342
335
  if (rpcReceipt) {
343
- const receipt = TransactionReceipt.fromRpc(rpcReceipt as any)
336
+ const receipt = TransactionReceipt.fromRpc(rpcReceipt as Parameters<typeof TransactionReceipt.fromRpc>[0])
344
337
  if (receipt?.status === 'success') {
345
338
  return 'success'
346
339
  } else if (receipt?.status === 'reverted') {
@@ -5,7 +5,7 @@ import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js'
5
5
  import { FeeToken } from '../rpc-relayer/relayer.gen.js'
6
6
 
7
7
  export class PkRelayer implements Relayer {
8
- public readonly kind: 'relayer' = 'relayer'
8
+ public readonly kind = 'relayer'
9
9
  public readonly type = 'pk'
10
10
  public readonly id = 'pk'
11
11
  private readonly relayer: LocalRelayer
@@ -114,9 +114,10 @@ export class PkRelayer implements Relayer {
114
114
  feeOptions(
115
115
  wallet: Address.Address,
116
116
  chainId: number,
117
+ to: Address.Address,
117
118
  calls: Payload.Call[],
118
119
  ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
119
- return this.relayer.feeOptions(wallet, chainId, calls)
120
+ return this.relayer.feeOptions(wallet, chainId, to, calls)
120
121
  }
121
122
 
122
123
  async relay(to: Address.Address, data: Hex.Hex, chainId: number, _?: FeeQuote): Promise<{ opHash: Hex.Hex }> {
@@ -131,7 +132,7 @@ export class PkRelayer implements Relayer {
131
132
  return this.relayer.status(opHash, chainId)
132
133
  }
133
134
 
134
- async checkPrecondition(precondition: Precondition.Precondition): Promise<boolean> {
135
+ async checkPrecondition(_precondition: Precondition.Precondition): Promise<boolean> {
135
136
  // TODO: Implement precondition check
136
137
  return true
137
138
  }
@@ -3,7 +3,7 @@ import { Payload } from '@0xsequence/wallet-primitives'
3
3
  import { AbiFunction, Address, Bytes, Hex } from 'ox'
4
4
  import { FeeOption, FeeQuote, OperationStatus, Relayer } from '../index.js'
5
5
  export class SequenceRelayer implements Relayer {
6
- public readonly kind: 'relayer' = 'relayer'
6
+ public readonly kind = 'relayer'
7
7
  public readonly type = 'sequence'
8
8
  readonly id = 'sequence'
9
9
 
@@ -36,9 +36,9 @@ export class SequenceRelayer implements Relayer {
36
36
  async feeOptions(
37
37
  wallet: Address.Address,
38
38
  _chainId: number,
39
+ to: Address.Address,
39
40
  calls: Payload.Call[],
40
41
  ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
41
- const to = wallet // TODO: this might be the guest module
42
42
  const execute = AbiFunction.from('function execute(bytes calldata _payload, bytes calldata _signature)')
43
43
  const payload = Payload.encode({ type: 'call', space: 0n, nonce: 0n, calls }, to)
44
44
  const signature = '0x0001' // TODO: use a stub signature
@@ -52,7 +52,7 @@ export class SequenceRelayer implements Relayer {
52
52
  }
53
53
  }
54
54
 
55
- async checkPrecondition(precondition: TransactionPrecondition): Promise<boolean> {
55
+ async checkPrecondition(_precondition: TransactionPrecondition): Promise<boolean> {
56
56
  // TODO: implement
57
57
  return false
58
58
  }
@@ -36,8 +36,8 @@ describe('Preconditions Codec', () => {
36
36
 
37
37
  describe('decodePrecondition', () => {
38
38
  it('should return undefined for null/undefined input', () => {
39
- expect(decodePrecondition(null as any)).toBeUndefined()
40
- expect(decodePrecondition(undefined as any)).toBeUndefined()
39
+ expect(decodePrecondition(null as unknown as TransactionPrecondition)).toBeUndefined()
40
+ expect(decodePrecondition(undefined as unknown as TransactionPrecondition)).toBeUndefined()
41
41
  })
42
42
 
43
43
  it('should decode native balance precondition with only min', () => {
@@ -231,8 +231,8 @@ describe('Preconditions Codec', () => {
231
231
  it('should handle malformed addresses gracefully', () => {
232
232
  const intent: TransactionPrecondition = {
233
233
  type: 'native-balance',
234
- ownerAddress: 'invalid-address' as any,
235
- tokenAddress: NATIVE_TOKEN_ADDRESS,
234
+ ownerAddress: 'invalid-address',
235
+ tokenAddress: NATIVE_TOKEN_ADDRESS.toString(),
236
236
  chainId: ARBITRUM_CHAIN_ID,
237
237
  minAmount: BigInt('1000000000000000000'),
238
238
  }
@@ -243,13 +243,13 @@ describe('Preconditions Codec', () => {
243
243
  })
244
244
 
245
245
  it('should handle malformed BigInt values gracefully', () => {
246
- const intent: TransactionPrecondition = {
246
+ const intent = {
247
247
  type: 'native-balance',
248
- ownerAddress: TEST_ADDRESS,
249
- tokenAddress: NATIVE_TOKEN_ADDRESS,
248
+ ownerAddress: TEST_ADDRESS.toString(),
249
+ tokenAddress: NATIVE_TOKEN_ADDRESS.toString(),
250
250
  chainId: ARBITRUM_CHAIN_ID,
251
- minAmount: 'not-a-number' as any,
252
- }
251
+ minAmount: 'not-a-number',
252
+ } as unknown as TransactionPrecondition
253
253
 
254
254
  const result = decodePrecondition(intent)
255
255
  expect(result).toBeUndefined()
@@ -316,8 +316,8 @@ describe('Preconditions Codec', () => {
316
316
  },
317
317
  {
318
318
  type: 'native-balance',
319
- ownerAddress: 'invalid-address' as any,
320
- tokenAddress: NATIVE_TOKEN_ADDRESS,
319
+ ownerAddress: 'invalid-address',
320
+ tokenAddress: NATIVE_TOKEN_ADDRESS.toString(),
321
321
  chainId: ARBITRUM_CHAIN_ID,
322
322
  minAmount: BigInt('1000000000000000000'),
323
323
  },
@@ -1,4 +1,4 @@
1
- import { Address, Provider, RpcTransport, Secp256k1 } from 'ox'
1
+ import { Address, Hex, Secp256k1 } from 'ox'
2
2
  import { describe, expect, it, vi } from 'vitest'
3
3
  import {
4
4
  Erc1155ApprovalPrecondition,
@@ -9,49 +9,50 @@ import {
9
9
  Erc721OwnershipPrecondition,
10
10
  NativeBalancePrecondition,
11
11
  } from '../../src/preconditions/types.js'
12
- import { LocalRelayer } from '../../src/standard/local.js'
13
- import { CAN_RUN_LIVE, RPC_URL } from '../../../../wallet/core/test/constants'
12
+ import {
13
+ LocalRelayer,
14
+ type GenericProvider,
15
+ } from '../../src/relayer/standard/local.js'
14
16
  import { Network } from '@0xsequence/wallet-primitives'
15
17
 
18
+ const CAN_RUN_LIVE = false
19
+ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
16
20
  const ERC20_IMPLICIT_MINT_CONTRACT = '0x041E0CDC028050519C8e6485B2d9840caf63773F'
17
21
 
18
22
  function randomAddress(): Address.Address {
19
23
  return Address.fromPublicKey(Secp256k1.getPublicKey({ privateKey: Secp256k1.randomPrivateKey() }))
20
24
  }
21
25
 
26
+ function createMockProvider(): GenericProvider {
27
+ return {
28
+ sendTransaction: vi.fn(),
29
+ getBalance: vi.fn(),
30
+ call: vi.fn(),
31
+ getTransactionReceipt: vi.fn(),
32
+ }
33
+ }
34
+
22
35
  describe('Preconditions', () => {
23
- const getProvider = async (): Promise<{ provider: Provider.Provider; chainId: number }> => {
24
- let provider: Provider.Provider
25
- let chainId: number = Network.ChainId.MAINNET
36
+ const getProvider = async (): Promise<{ provider: GenericProvider; chainId: number }> => {
37
+ const chainId = Network.ChainId.MAINNET
26
38
  if (CAN_RUN_LIVE) {
27
- provider = Provider.from(RpcTransport.fromHttp(RPC_URL!!))
28
- chainId = Number(await provider.request({ method: 'eth_chainId' }))
29
- } else {
30
- provider = {
31
- request: vi.fn(),
32
- on: vi.fn(),
33
- removeListener: vi.fn(),
34
- call: vi.fn(),
35
- sendTransaction: vi.fn(),
36
- getBalance: vi.fn(),
37
- } as unknown as Provider.Provider
39
+ throw new Error('Live tests not configured: set up RPC and GenericProvider adapter')
38
40
  }
39
-
40
- return { provider: provider!, chainId }
41
+ const provider = createMockProvider()
42
+ return { provider, chainId }
41
43
  }
42
44
 
43
45
  const testWalletAddress = randomAddress()
44
46
 
45
- const requireContractDeployed = async (provider: Provider.Provider, contract: Address.Address) => {
46
- const code = await provider.request({ method: 'eth_getCode', params: [contract, 'latest'] })
47
- if (code === '0x') {
48
- throw new Error(`Contract ${contract} not deployed`)
47
+ const requireContractDeployed = async (_provider: GenericProvider, _contract: Address.Address) => {
48
+ if (CAN_RUN_LIVE) {
49
+ throw new Error('Live contract check not implemented')
49
50
  }
50
51
  }
51
52
 
52
53
  it('should create and check native balance precondition', async () => {
53
54
  const { provider, chainId } = await getProvider()
54
- const relayer = new LocalRelayer(provider as any)
55
+ const relayer = new LocalRelayer(provider)
55
56
 
56
57
  const precondition = new NativeBalancePrecondition(
57
58
  testWalletAddress,
@@ -59,225 +60,183 @@ describe('Preconditions', () => {
59
60
  2000000000000000000n, // 2 ETH max
60
61
  )
61
62
 
62
- const intentPrecondition = {
63
+ const transactionPrecondition = {
63
64
  type: precondition.type(),
64
- chainId: chainId.toString(),
65
- data: JSON.stringify({
66
- address: precondition.address.toString(),
67
- min: precondition.min?.toString(),
68
- max: precondition.max?.toString(),
69
- }),
65
+ chainId,
66
+ ownerAddress: precondition.address.toString(),
67
+ tokenAddress: ZERO_ADDRESS,
68
+ minAmount: precondition.min ?? 0n,
70
69
  }
71
70
 
72
- if (!CAN_RUN_LIVE) {
73
- // Mock the balance check
74
- ;(provider as any).request.mockResolvedValue('0x16345785d8a0000') // 1.5 ETH in hex
75
- }
71
+ vi.mocked(provider.getBalance).mockResolvedValue(1500000000000000000n) // 1.5 ETH
76
72
 
77
- const isValid = await relayer.checkPrecondition(intentPrecondition)
73
+ const isValid = await relayer.checkPrecondition(transactionPrecondition)
78
74
  expect(isValid).toBe(true)
79
75
  })
80
76
 
81
77
  it('should create and check ERC20 balance precondition', async () => {
82
78
  const { provider, chainId } = await getProvider()
83
- const relayer = new LocalRelayer(provider as any)
84
- await requireContractDeployed(provider, ERC20_IMPLICIT_MINT_CONTRACT)
79
+ const relayer = new LocalRelayer(provider)
80
+ await requireContractDeployed(provider, Address.from(ERC20_IMPLICIT_MINT_CONTRACT))
85
81
 
86
82
  const precondition = new Erc20BalancePrecondition(
87
83
  testWalletAddress,
88
- ERC20_IMPLICIT_MINT_CONTRACT,
84
+ Address.from(ERC20_IMPLICIT_MINT_CONTRACT),
89
85
  1000000n, // 1 token min
90
86
  2000000n, // 2 tokens max
91
87
  )
92
88
 
93
- const intentPrecondition = {
89
+ const transactionPrecondition = {
94
90
  type: precondition.type(),
95
- chainId: chainId.toString(),
96
- data: JSON.stringify({
97
- address: precondition.address.toString(),
98
- token: precondition.token.toString(),
99
- min: precondition.min?.toString(),
100
- max: precondition.max?.toString(),
101
- }),
91
+ chainId,
92
+ ownerAddress: precondition.address.toString(),
93
+ tokenAddress: precondition.token.toString(),
94
+ minAmount: precondition.min ?? 0n,
102
95
  }
103
96
 
104
- if (!CAN_RUN_LIVE) {
105
- // Mock the balanceOf call
106
- ;(provider as any).call.mockResolvedValue('0x1e8480') // 1.5 tokens in hex
107
- }
97
+ vi.mocked(provider.call).mockResolvedValue('0x1e8480' as Hex.Hex) // 1.5 tokens in hex
108
98
 
109
- const isValid = await relayer.checkPrecondition(intentPrecondition)
99
+ const isValid = await relayer.checkPrecondition(transactionPrecondition)
110
100
  expect(isValid).toBe(true)
111
101
  })
112
102
 
113
103
  it('should create and check ERC20 approval precondition', async () => {
114
104
  const { provider, chainId } = await getProvider()
115
- const relayer = new LocalRelayer(provider as any)
116
- await requireContractDeployed(provider, ERC20_IMPLICIT_MINT_CONTRACT)
105
+ const relayer = new LocalRelayer(provider)
106
+ await requireContractDeployed(provider, Address.from(ERC20_IMPLICIT_MINT_CONTRACT))
117
107
 
118
108
  const operator = randomAddress()
119
109
  const precondition = new Erc20ApprovalPrecondition(
120
110
  testWalletAddress,
121
- ERC20_IMPLICIT_MINT_CONTRACT,
111
+ Address.from(ERC20_IMPLICIT_MINT_CONTRACT),
122
112
  operator,
123
113
  1000000n, // 1 token min approval
124
114
  )
125
115
 
126
- const intentPrecondition = {
116
+ const transactionPrecondition = {
127
117
  type: precondition.type(),
128
- chainId: chainId.toString(),
129
- data: JSON.stringify({
130
- address: precondition.address.toString(),
131
- token: precondition.token.toString(),
132
- operator: precondition.operator.toString(),
133
- min: precondition.min.toString(),
134
- }),
118
+ chainId,
119
+ ownerAddress: precondition.address.toString(),
120
+ tokenAddress: precondition.token.toString(),
121
+ minAmount: precondition.min,
135
122
  }
136
123
 
137
- if (!CAN_RUN_LIVE) {
138
- // Mock the allowance call
139
- ;(provider as any).call.mockResolvedValue('0x1e8480') // 1.5 tokens in hex
140
- }
124
+ vi.mocked(provider.call).mockResolvedValue('0x1e8480' as Hex.Hex) // 1.5 tokens in hex
141
125
 
142
- const isValid = await relayer.checkPrecondition(intentPrecondition)
126
+ const isValid = await relayer.checkPrecondition(transactionPrecondition)
143
127
  expect(isValid).toBe(true)
144
128
  })
145
129
 
146
130
  it('should create and check ERC721 ownership precondition', async () => {
147
131
  const { provider, chainId } = await getProvider()
148
- const relayer = new LocalRelayer(provider as any)
149
- await requireContractDeployed(provider, ERC20_IMPLICIT_MINT_CONTRACT)
132
+ const relayer = new LocalRelayer(provider)
133
+ await requireContractDeployed(provider, Address.from(ERC20_IMPLICIT_MINT_CONTRACT))
150
134
 
151
135
  const precondition = new Erc721OwnershipPrecondition(
152
136
  testWalletAddress,
153
- ERC20_IMPLICIT_MINT_CONTRACT,
137
+ Address.from(ERC20_IMPLICIT_MINT_CONTRACT),
154
138
  1n, // tokenId
155
139
  true, // must own
156
140
  )
157
141
 
158
- const intentPrecondition = {
142
+ const transactionPrecondition = {
159
143
  type: precondition.type(),
160
- chainId: chainId.toString(),
161
- data: JSON.stringify({
162
- address: precondition.address.toString(),
163
- token: precondition.token.toString(),
164
- tokenId: precondition.tokenId.toString(),
165
- owned: precondition.owned,
166
- }),
144
+ chainId,
145
+ ownerAddress: precondition.address.toString(),
146
+ tokenAddress: precondition.token.toString(),
147
+ minAmount: 0n,
167
148
  }
168
149
 
169
- if (!CAN_RUN_LIVE) {
170
- // Mock the ownerOf call
171
- ;(provider as any).call.mockResolvedValue(
172
- '0x000000000000000000000000' + testWalletAddress.toString().slice(2).toLowerCase(),
173
- )
174
- }
150
+ vi.mocked(provider.call).mockResolvedValue(
151
+ ('0x000000000000000000000000' + testWalletAddress.toString().slice(2).toLowerCase()) as Hex.Hex,
152
+ )
175
153
 
176
- const isValid = await relayer.checkPrecondition(intentPrecondition)
154
+ const isValid = await relayer.checkPrecondition(transactionPrecondition)
177
155
  expect(isValid).toBe(true)
178
156
  })
179
157
 
180
158
  it('should create and check ERC721 approval precondition', async () => {
181
159
  const { provider, chainId } = await getProvider()
182
- const relayer = new LocalRelayer(provider as any)
183
- await requireContractDeployed(provider, ERC20_IMPLICIT_MINT_CONTRACT)
160
+ const relayer = new LocalRelayer(provider)
161
+ await requireContractDeployed(provider, Address.from(ERC20_IMPLICIT_MINT_CONTRACT))
184
162
 
185
163
  const operator = randomAddress()
186
164
  const precondition = new Erc721ApprovalPrecondition(
187
165
  testWalletAddress,
188
- ERC20_IMPLICIT_MINT_CONTRACT,
166
+ Address.from(ERC20_IMPLICIT_MINT_CONTRACT),
189
167
  1n, // tokenId
190
168
  operator,
191
169
  )
192
170
 
193
- const intentPrecondition = {
171
+ const transactionPrecondition = {
194
172
  type: precondition.type(),
195
- chainId: chainId.toString(),
196
- data: JSON.stringify({
197
- address: precondition.address.toString(),
198
- token: precondition.token.toString(),
199
- tokenId: precondition.tokenId.toString(),
200
- operator: precondition.operator.toString(),
201
- }),
173
+ chainId,
174
+ ownerAddress: precondition.address.toString(),
175
+ tokenAddress: precondition.token.toString(),
176
+ minAmount: 0n,
202
177
  }
203
178
 
204
- if (!CAN_RUN_LIVE) {
205
- // Mock the getApproved call
206
- ;(provider as any).call.mockResolvedValue(
207
- '0x000000000000000000000000' + operator.toString().slice(2).toLowerCase(),
208
- )
209
- }
179
+ // getApproved returns 32-byte word: 12 zero bytes + 20-byte address. Codec uses ownerAddress as operator.
180
+ const approvedHex =
181
+ '0x' + '0'.repeat(24) + testWalletAddress.toString().slice(2).toLowerCase()
182
+ vi.mocked(provider.call).mockResolvedValue(approvedHex as Hex.Hex)
210
183
 
211
- const isValid = await relayer.checkPrecondition(intentPrecondition)
184
+ const isValid = await relayer.checkPrecondition(transactionPrecondition)
212
185
  expect(isValid).toBe(true)
213
186
  })
214
187
 
215
188
  it('should create and check ERC1155 balance precondition', async () => {
216
189
  const { provider, chainId } = await getProvider()
217
- const relayer = new LocalRelayer(provider as any)
218
- await requireContractDeployed(provider, ERC20_IMPLICIT_MINT_CONTRACT)
190
+ const relayer = new LocalRelayer(provider)
191
+ await requireContractDeployed(provider, Address.from(ERC20_IMPLICIT_MINT_CONTRACT))
219
192
 
220
193
  const precondition = new Erc1155BalancePrecondition(
221
194
  testWalletAddress,
222
- ERC20_IMPLICIT_MINT_CONTRACT,
195
+ Address.from(ERC20_IMPLICIT_MINT_CONTRACT),
223
196
  1n, // tokenId
224
197
  1000000n, // 1 token min
225
198
  2000000n, // 2 tokens max
226
199
  )
227
200
 
228
- const intentPrecondition = {
201
+ const transactionPrecondition = {
229
202
  type: precondition.type(),
230
- chainId: chainId.toString(),
231
- data: JSON.stringify({
232
- address: precondition.address.toString(),
233
- token: precondition.token.toString(),
234
- tokenId: precondition.tokenId.toString(),
235
- min: precondition.min?.toString(),
236
- max: precondition.max?.toString(),
237
- }),
203
+ chainId,
204
+ ownerAddress: precondition.address.toString(),
205
+ tokenAddress: precondition.token.toString(),
206
+ minAmount: precondition.min ?? 0n,
238
207
  }
239
208
 
240
- if (!CAN_RUN_LIVE) {
241
- // Mock the balanceOf call
242
- ;(provider as any).call.mockResolvedValue('0x1e8480') // 1.5 tokens in hex
243
- }
209
+ vi.mocked(provider.call).mockResolvedValue('0x1e8480' as Hex.Hex) // 1.5 tokens in hex
244
210
 
245
- const isValid = await relayer.checkPrecondition(intentPrecondition)
211
+ const isValid = await relayer.checkPrecondition(transactionPrecondition)
246
212
  expect(isValid).toBe(true)
247
213
  })
248
214
 
249
215
  it('should create and check ERC1155 approval precondition', async () => {
250
216
  const { provider, chainId } = await getProvider()
251
- const relayer = new LocalRelayer(provider as any)
252
- await requireContractDeployed(provider, ERC20_IMPLICIT_MINT_CONTRACT)
217
+ const relayer = new LocalRelayer(provider)
218
+ await requireContractDeployed(provider, Address.from(ERC20_IMPLICIT_MINT_CONTRACT))
253
219
 
254
220
  const operator = randomAddress()
255
221
  const precondition = new Erc1155ApprovalPrecondition(
256
222
  testWalletAddress,
257
- ERC20_IMPLICIT_MINT_CONTRACT,
223
+ Address.from(ERC20_IMPLICIT_MINT_CONTRACT),
258
224
  1n, // tokenId
259
225
  operator,
260
226
  1000000n, // 1 token min approval
261
227
  )
262
228
 
263
- const intentPrecondition = {
229
+ const transactionPrecondition = {
264
230
  type: precondition.type(),
265
- chainId: chainId.toString(),
266
- data: JSON.stringify({
267
- address: precondition.address.toString(),
268
- token: precondition.token.toString(),
269
- tokenId: precondition.tokenId.toString(),
270
- operator: precondition.operator.toString(),
271
- min: precondition.min.toString(),
272
- }),
231
+ chainId,
232
+ ownerAddress: precondition.address.toString(),
233
+ tokenAddress: precondition.token.toString(),
234
+ minAmount: precondition.min,
273
235
  }
274
236
 
275
- if (!CAN_RUN_LIVE) {
276
- // Mock the isApprovedForAll call
277
- ;(provider as any).call.mockResolvedValue('0x1') // true
278
- }
237
+ vi.mocked(provider.call).mockResolvedValue('0x1' as Hex.Hex) // true
279
238
 
280
- const isValid = await relayer.checkPrecondition(intentPrecondition)
239
+ const isValid = await relayer.checkPrecondition(transactionPrecondition)
281
240
  expect(isValid).toBe(true)
282
241
  })
283
242
  })