eco-solver 0.0.1-security → 1.5.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.
Potentially problematic release.
This version of eco-solver might be problematic. Click here for more details.
- package/.eslintignore +8 -0
- package/.eslintrc.js +24 -0
- package/.github/workflows/ci.yaml +38 -0
- package/.nvmrc +1 -0
- package/.prettierignore +3 -0
- package/.prettierrc +8 -0
- package/Dockerfile +11 -0
- package/LICENSE +21 -0
- package/README.md +29 -5
- package/config/default.ts +135 -0
- package/config/development.ts +95 -0
- package/config/preproduction.ts +17 -0
- package/config/production.ts +17 -0
- package/config/staging.ts +17 -0
- package/config/test.ts +7 -0
- package/index.js +43 -0
- package/jest.config.ts +14 -0
- package/nest-cli.json +8 -0
- package/package.json +117 -6
- package/src/api/api.module.ts +27 -0
- package/src/api/balance.controller.ts +41 -0
- package/src/api/quote.controller.ts +54 -0
- package/src/api/tests/balance.controller.spec.ts +113 -0
- package/src/api/tests/quote.controller.spec.ts +83 -0
- package/src/app.module.ts +74 -0
- package/src/balance/balance.module.ts +14 -0
- package/src/balance/balance.service.ts +230 -0
- package/src/balance/balance.ws.service.ts +104 -0
- package/src/balance/types.ts +16 -0
- package/src/bullmq/bullmq.helper.ts +41 -0
- package/src/bullmq/processors/eth-ws.processor.ts +47 -0
- package/src/bullmq/processors/inbox.processor.ts +55 -0
- package/src/bullmq/processors/interval.processor.ts +54 -0
- package/src/bullmq/processors/processor.module.ts +14 -0
- package/src/bullmq/processors/signer.processor.ts +41 -0
- package/src/bullmq/processors/solve-intent.processor.ts +73 -0
- package/src/bullmq/processors/tests/solve-intent.processor.spec.ts +3 -0
- package/src/bullmq/utils/queue.ts +22 -0
- package/src/chain-monitor/chain-monitor.module.ts +12 -0
- package/src/chain-monitor/chain-sync.service.ts +134 -0
- package/src/chain-monitor/tests/chain-sync.service.spec.ts +190 -0
- package/src/commander/.eslintrc.js +6 -0
- package/src/commander/balance/balance-command.module.ts +12 -0
- package/src/commander/balance/balance.command.ts +73 -0
- package/src/commander/command-main.ts +15 -0
- package/src/commander/commander-app.module.ts +31 -0
- package/src/commander/eco-config.command.ts +20 -0
- package/src/commander/safe/safe-command.module.ts +11 -0
- package/src/commander/safe/safe.command.ts +70 -0
- package/src/commander/transfer/client.command.ts +24 -0
- package/src/commander/transfer/transfer-command.module.ts +26 -0
- package/src/commander/transfer/transfer.command.ts +138 -0
- package/src/commander/utils.ts +8 -0
- package/src/common/chains/definitions/arbitrum.ts +12 -0
- package/src/common/chains/definitions/base.ts +21 -0
- package/src/common/chains/definitions/eco.ts +54 -0
- package/src/common/chains/definitions/ethereum.ts +22 -0
- package/src/common/chains/definitions/helix.ts +53 -0
- package/src/common/chains/definitions/mantle.ts +12 -0
- package/src/common/chains/definitions/optimism.ts +22 -0
- package/src/common/chains/definitions/polygon.ts +12 -0
- package/src/common/chains/supported.ts +26 -0
- package/src/common/chains/transport.ts +19 -0
- package/src/common/errors/eco-error.ts +155 -0
- package/src/common/events/constants.ts +3 -0
- package/src/common/events/viem.ts +22 -0
- package/src/common/logging/eco-log-message.ts +74 -0
- package/src/common/redis/constants.ts +55 -0
- package/src/common/redis/redis-connection-utils.ts +106 -0
- package/src/common/routes/constants.ts +3 -0
- package/src/common/utils/objects.ts +34 -0
- package/src/common/utils/strings.ts +49 -0
- package/src/common/utils/tests/objects.spec.ts +23 -0
- package/src/common/utils/tests/strings.spec.ts +22 -0
- package/src/common/viem/contracts.ts +25 -0
- package/src/common/viem/tests/utils.spec.ts +115 -0
- package/src/common/viem/utils.ts +78 -0
- package/src/contracts/ERC20.contract.ts +389 -0
- package/src/contracts/EntryPoint.V6.contract.ts +1309 -0
- package/src/contracts/KernelAccount.abi.ts +87 -0
- package/src/contracts/OwnableExecutor.abi.ts +128 -0
- package/src/contracts/SimpleAccount.contract.ts +524 -0
- package/src/contracts/inbox.ts +8 -0
- package/src/contracts/index.ts +9 -0
- package/src/contracts/intent-source.ts +55 -0
- package/src/contracts/interfaces/index.ts +1 -0
- package/src/contracts/interfaces/prover.interface.ts +22 -0
- package/src/contracts/prover.ts +9 -0
- package/src/contracts/tests/erc20.contract.spec.ts +59 -0
- package/src/contracts/utils.ts +31 -0
- package/src/decoder/decoder.interface.ts +3 -0
- package/src/decoder/tests/utils.spec.ts +36 -0
- package/src/decoder/utils.ts +24 -0
- package/src/decorators/cacheable.decorator.ts +48 -0
- package/src/eco-configs/aws-config.service.ts +75 -0
- package/src/eco-configs/eco-config.module.ts +44 -0
- package/src/eco-configs/eco-config.service.ts +220 -0
- package/src/eco-configs/eco-config.types.ts +278 -0
- package/src/eco-configs/interfaces/config-source.interface.ts +3 -0
- package/src/eco-configs/tests/aws-config.service.spec.ts +52 -0
- package/src/eco-configs/tests/eco-config.service.spec.ts +137 -0
- package/src/eco-configs/tests/utils.spec.ts +84 -0
- package/src/eco-configs/utils.ts +49 -0
- package/src/fee/fee.module.ts +10 -0
- package/src/fee/fee.service.ts +467 -0
- package/src/fee/tests/fee.service.spec.ts +909 -0
- package/src/fee/tests/utils.spec.ts +49 -0
- package/src/fee/types.ts +44 -0
- package/src/fee/utils.ts +23 -0
- package/src/flags/flags.module.ts +10 -0
- package/src/flags/flags.service.ts +112 -0
- package/src/flags/tests/flags.service.spec.ts +68 -0
- package/src/flags/utils.ts +22 -0
- package/src/health/constants.ts +1 -0
- package/src/health/health.controller.ts +23 -0
- package/src/health/health.module.ts +25 -0
- package/src/health/health.service.ts +40 -0
- package/src/health/indicators/balance.indicator.ts +196 -0
- package/src/health/indicators/eco-redis.indicator.ts +23 -0
- package/src/health/indicators/git-commit.indicator.ts +67 -0
- package/src/health/indicators/mongodb.indicator.ts +11 -0
- package/src/health/indicators/permission.indicator.ts +64 -0
- package/src/intent/create-intent.service.ts +129 -0
- package/src/intent/feasable-intent.service.ts +80 -0
- package/src/intent/fulfill-intent.service.ts +318 -0
- package/src/intent/intent.controller.ts +199 -0
- package/src/intent/intent.module.ts +49 -0
- package/src/intent/schemas/intent-call-data.schema.ts +16 -0
- package/src/intent/schemas/intent-data.schema.ts +114 -0
- package/src/intent/schemas/intent-source.schema.ts +33 -0
- package/src/intent/schemas/intent-token-amount.schema.ts +14 -0
- package/src/intent/schemas/reward-data.schema.ts +48 -0
- package/src/intent/schemas/route-data.schema.ts +52 -0
- package/src/intent/schemas/watch-event.schema.ts +32 -0
- package/src/intent/tests/create-intent.service.spec.ts +215 -0
- package/src/intent/tests/feasable-intent.service.spec.ts +155 -0
- package/src/intent/tests/fulfill-intent.service.spec.ts +564 -0
- package/src/intent/tests/utils-intent.service.spec.ts +308 -0
- package/src/intent/tests/utils.spec.ts +62 -0
- package/src/intent/tests/validate-intent.service.spec.ts +297 -0
- package/src/intent/tests/validation.service.spec.ts +337 -0
- package/src/intent/utils-intent.service.ts +168 -0
- package/src/intent/utils.ts +37 -0
- package/src/intent/validate-intent.service.ts +176 -0
- package/src/intent/validation.sevice.ts +223 -0
- package/src/interceptors/big-int.interceptor.ts +30 -0
- package/src/intervals/interval.module.ts +18 -0
- package/src/intervals/retry-infeasable-intents.service.ts +89 -0
- package/src/intervals/tests/retry-infeasable-intents.service.spec.ts +167 -0
- package/src/kms/errors.ts +0 -0
- package/src/kms/kms.module.ts +12 -0
- package/src/kms/kms.service.ts +65 -0
- package/src/kms/tests/kms.service.spec.ts +60 -0
- package/src/liquidity-manager/jobs/check-balances-cron.job.ts +229 -0
- package/src/liquidity-manager/jobs/liquidity-manager.job.ts +52 -0
- package/src/liquidity-manager/jobs/rebalance.job.ts +61 -0
- package/src/liquidity-manager/liquidity-manager.module.ts +29 -0
- package/src/liquidity-manager/processors/base.processor.ts +117 -0
- package/src/liquidity-manager/processors/eco-protocol-intents.processor.ts +34 -0
- package/src/liquidity-manager/processors/grouped-jobs.processor.ts +103 -0
- package/src/liquidity-manager/queues/liquidity-manager.queue.ts +48 -0
- package/src/liquidity-manager/schemas/rebalance-token.schema.ts +32 -0
- package/src/liquidity-manager/schemas/rebalance.schema.ts +32 -0
- package/src/liquidity-manager/services/liquidity-manager.service.ts +188 -0
- package/src/liquidity-manager/services/liquidity-provider.service.ts +25 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service.spec.ts +125 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service.ts +117 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/utils/get-transaction-hashes.ts +16 -0
- package/src/liquidity-manager/tests/liquidity-manager.service.spec.ts +142 -0
- package/src/liquidity-manager/types/token-state.enum.ts +5 -0
- package/src/liquidity-manager/types/types.d.ts +52 -0
- package/src/liquidity-manager/utils/address.ts +5 -0
- package/src/liquidity-manager/utils/math.ts +9 -0
- package/src/liquidity-manager/utils/serialize.spec.ts +24 -0
- package/src/liquidity-manager/utils/serialize.ts +47 -0
- package/src/liquidity-manager/utils/token.ts +91 -0
- package/src/main.ts +63 -0
- package/src/nest-redlock/nest-redlock.config.ts +14 -0
- package/src/nest-redlock/nest-redlock.interface.ts +5 -0
- package/src/nest-redlock/nest-redlock.module.ts +64 -0
- package/src/nest-redlock/nest-redlock.service.ts +59 -0
- package/src/prover/proof.service.ts +184 -0
- package/src/prover/prover.module.ts +10 -0
- package/src/prover/tests/proof.service.spec.ts +154 -0
- package/src/quote/dto/quote.intent.data.dto.ts +35 -0
- package/src/quote/dto/quote.reward.data.dto.ts +67 -0
- package/src/quote/dto/quote.route.data.dto.ts +71 -0
- package/src/quote/dto/types.ts +18 -0
- package/src/quote/errors.ts +215 -0
- package/src/quote/quote.module.ts +17 -0
- package/src/quote/quote.service.ts +299 -0
- package/src/quote/schemas/quote-call.schema.ts +16 -0
- package/src/quote/schemas/quote-intent.schema.ts +27 -0
- package/src/quote/schemas/quote-reward.schema.ts +24 -0
- package/src/quote/schemas/quote-route.schema.ts +30 -0
- package/src/quote/schemas/quote-token.schema.ts +14 -0
- package/src/quote/tests/quote.service.spec.ts +444 -0
- package/src/sign/atomic-signer.service.ts +24 -0
- package/src/sign/atomic.nonce.service.ts +114 -0
- package/src/sign/kms-account/kmsToAccount.ts +73 -0
- package/src/sign/kms-account/signKms.ts +30 -0
- package/src/sign/kms-account/signKmsTransaction.ts +37 -0
- package/src/sign/kms-account/signKmsTypedData.ts +21 -0
- package/src/sign/nonce.service.ts +89 -0
- package/src/sign/schemas/nonce.schema.ts +36 -0
- package/src/sign/sign.controller.ts +52 -0
- package/src/sign/sign.helper.ts +23 -0
- package/src/sign/sign.module.ts +27 -0
- package/src/sign/signer-kms.service.ts +27 -0
- package/src/sign/signer.service.ts +26 -0
- package/src/solver/filters/tests/valid-smart-wallet.service.spec.ts +87 -0
- package/src/solver/filters/valid-smart-wallet.service.ts +58 -0
- package/src/solver/solver.module.ts +10 -0
- package/src/transaction/multichain-public-client.service.ts +15 -0
- package/src/transaction/smart-wallets/kernel/actions/encodeData.kernel.ts +57 -0
- package/src/transaction/smart-wallets/kernel/create-kernel-client-v2.account.ts +183 -0
- package/src/transaction/smart-wallets/kernel/create.kernel.account.ts +270 -0
- package/src/transaction/smart-wallets/kernel/index.ts +2 -0
- package/src/transaction/smart-wallets/kernel/kernel-account-client-v2.service.ts +90 -0
- package/src/transaction/smart-wallets/kernel/kernel-account-client.service.ts +107 -0
- package/src/transaction/smart-wallets/kernel/kernel-account.client.ts +105 -0
- package/src/transaction/smart-wallets/kernel/kernel-account.config.ts +34 -0
- package/src/transaction/smart-wallets/simple-account/create.simple.account.ts +19 -0
- package/src/transaction/smart-wallets/simple-account/index.ts +2 -0
- package/src/transaction/smart-wallets/simple-account/simple-account-client.service.ts +42 -0
- package/src/transaction/smart-wallets/simple-account/simple-account.client.ts +83 -0
- package/src/transaction/smart-wallets/simple-account/simple-account.config.ts +5 -0
- package/src/transaction/smart-wallets/smart-wallet.types.ts +38 -0
- package/src/transaction/smart-wallets/utils.ts +14 -0
- package/src/transaction/transaction.module.ts +25 -0
- package/src/transaction/viem_multichain_client.service.ts +100 -0
- package/src/transforms/viem-address.decorator.ts +14 -0
- package/src/utils/bigint.ts +44 -0
- package/src/utils/types.ts +18 -0
- package/src/watch/intent/tests/watch-create-intent.service.spec.ts +257 -0
- package/src/watch/intent/tests/watch-fulfillment.service.spec.ts +141 -0
- package/src/watch/intent/watch-create-intent.service.ts +106 -0
- package/src/watch/intent/watch-event.service.ts +133 -0
- package/src/watch/intent/watch-fulfillment.service.ts +115 -0
- package/src/watch/watch.module.ts +13 -0
- package/test/app.e2e-spec.ts +21 -0
- package/test/jest-e2e.json +9 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +29 -0
@@ -0,0 +1,308 @@
|
|
1
|
+
const mockDecodeFunctionData = jest.fn()
|
2
|
+
import { createMock, DeepMocked } from '@golevelup/ts-jest'
|
3
|
+
import { EcoConfigService } from '../../eco-configs/eco-config.service'
|
4
|
+
import { Test, TestingModule } from '@nestjs/testing'
|
5
|
+
import { getModelToken } from '@nestjs/mongoose'
|
6
|
+
import { IntentSourceModel } from '../schemas/intent-source.schema'
|
7
|
+
import { Model } from 'mongoose'
|
8
|
+
import { UtilsIntentService } from '../utils-intent.service'
|
9
|
+
import { getQueueToken } from '@nestjs/bullmq'
|
10
|
+
import { QUEUES } from '../../common/redis/constants'
|
11
|
+
import { Queue } from 'bullmq'
|
12
|
+
import { EcoError } from '../../common/errors/eco-error'
|
13
|
+
import { getFunctionBytes } from '../../common/viem/contracts'
|
14
|
+
import { FulfillmentLog } from '@/contracts/inbox'
|
15
|
+
import { CallDataInterface } from '@/contracts'
|
16
|
+
import { ValidationChecks } from '@/intent/validation.sevice'
|
17
|
+
import { QuoteError } from '@/quote/errors'
|
18
|
+
|
19
|
+
jest.mock('viem', () => {
|
20
|
+
return {
|
21
|
+
...jest.requireActual('viem'),
|
22
|
+
decodeFunctionData: mockDecodeFunctionData,
|
23
|
+
}
|
24
|
+
})
|
25
|
+
|
26
|
+
describe('UtilsIntentService', () => {
|
27
|
+
let utilsIntentService: UtilsIntentService
|
28
|
+
let ecoConfigService: DeepMocked<EcoConfigService>
|
29
|
+
let intentModel: DeepMocked<Model<IntentSourceModel>>
|
30
|
+
const mockLogDebug = jest.fn()
|
31
|
+
const mockLogLog = jest.fn()
|
32
|
+
const mockLogWarn = jest.fn()
|
33
|
+
const address1 = '0x1111111111111111111111111111111111111111'
|
34
|
+
const address2 = '0x2222222222222222222222222222222222222222'
|
35
|
+
beforeEach(async () => {
|
36
|
+
const chainMod: TestingModule = await Test.createTestingModule({
|
37
|
+
providers: [
|
38
|
+
UtilsIntentService,
|
39
|
+
{ provide: EcoConfigService, useValue: createMock<EcoConfigService>() },
|
40
|
+
{
|
41
|
+
provide: getModelToken(IntentSourceModel.name),
|
42
|
+
useValue: createMock<Model<IntentSourceModel>>(),
|
43
|
+
},
|
44
|
+
],
|
45
|
+
})
|
46
|
+
.overrideProvider(getQueueToken(QUEUES.SOURCE_INTENT.queue))
|
47
|
+
.useValue(createMock<Queue>())
|
48
|
+
.compile()
|
49
|
+
|
50
|
+
utilsIntentService = chainMod.get(UtilsIntentService)
|
51
|
+
ecoConfigService = chainMod.get(EcoConfigService)
|
52
|
+
intentModel = chainMod.get(getModelToken(IntentSourceModel.name))
|
53
|
+
|
54
|
+
utilsIntentService['logger'].debug = mockLogDebug
|
55
|
+
utilsIntentService['logger'].log = mockLogLog
|
56
|
+
utilsIntentService['logger'].warn = mockLogWarn
|
57
|
+
})
|
58
|
+
|
59
|
+
afterEach(async () => {
|
60
|
+
// restore the spy created with spyOn
|
61
|
+
jest.restoreAllMocks()
|
62
|
+
mockLogDebug.mockClear()
|
63
|
+
mockLogLog.mockClear()
|
64
|
+
mockLogWarn.mockClear()
|
65
|
+
mockDecodeFunctionData.mockClear()
|
66
|
+
})
|
67
|
+
|
68
|
+
describe('on update models', () => {
|
69
|
+
const mockUpdateOne = jest.fn()
|
70
|
+
const model = { intent: { hash: '0x123' } } as any
|
71
|
+
beforeEach(() => {
|
72
|
+
intentModel.updateOne = mockUpdateOne
|
73
|
+
})
|
74
|
+
|
75
|
+
afterEach(() => {
|
76
|
+
mockUpdateOne.mockClear()
|
77
|
+
})
|
78
|
+
|
79
|
+
describe('on updateIntentModel', () => {
|
80
|
+
it('should updateOne model off the intent hash', async () => {
|
81
|
+
await utilsIntentService.updateIntentModel(model)
|
82
|
+
expect(mockUpdateOne).toHaveBeenCalledTimes(1)
|
83
|
+
expect(mockUpdateOne).toHaveBeenCalledWith({ 'intent.hash': model.intent.hash }, model)
|
84
|
+
})
|
85
|
+
})
|
86
|
+
|
87
|
+
describe('on updateInvalidIntentModel', () => {
|
88
|
+
it('should updateOne the model as invalid', async () => {
|
89
|
+
const invalidCause = {
|
90
|
+
supportedProver: false,
|
91
|
+
supportedTargets: true,
|
92
|
+
supportedSelectors: true,
|
93
|
+
validExpirationTime: true,
|
94
|
+
validDestination: true,
|
95
|
+
fulfillOnDifferentChain: true,
|
96
|
+
} as ValidationChecks
|
97
|
+
await utilsIntentService.updateInvalidIntentModel(model, invalidCause)
|
98
|
+
expect(mockUpdateOne).toHaveBeenCalledTimes(1)
|
99
|
+
expect(mockUpdateOne).toHaveBeenCalledWith(
|
100
|
+
{ 'intent.hash': model.intent.hash },
|
101
|
+
{ ...model, status: 'INVALID', receipt: invalidCause },
|
102
|
+
)
|
103
|
+
})
|
104
|
+
})
|
105
|
+
|
106
|
+
describe('on updateInfeasableIntentModel', () => {
|
107
|
+
it('should updateOne the model as infeasable', async () => {
|
108
|
+
const error = QuoteError.RouteIsInfeasable(10n, 9n)
|
109
|
+
await utilsIntentService.updateInfeasableIntentModel(model, error)
|
110
|
+
expect(mockUpdateOne).toHaveBeenCalledTimes(1)
|
111
|
+
expect(mockUpdateOne).toHaveBeenCalledWith(
|
112
|
+
{ 'intent.hash': model.intent.hash },
|
113
|
+
{ ...model, status: 'INFEASABLE', receipt: error },
|
114
|
+
)
|
115
|
+
})
|
116
|
+
})
|
117
|
+
})
|
118
|
+
|
119
|
+
// describe('on selectorsSupported', () => {
|
120
|
+
// it('should return false when target length is 0', async () => {
|
121
|
+
// const model = { intent: { route: { calls: [] } } } as any
|
122
|
+
// expect(utilsIntentService.selectorsSupported(model, {} as any)).toBe(false)
|
123
|
+
// expect(mockLogLog).toHaveBeenCalledTimes(1)
|
124
|
+
// expect(mockLogLog).toHaveBeenCalledWith({
|
125
|
+
// msg: 'validateIntent: Target/data invalid',
|
126
|
+
// intent: model.intent,
|
127
|
+
// })
|
128
|
+
// })
|
129
|
+
|
130
|
+
// it('should return false some target transactions fail to decode', async () => {
|
131
|
+
// const model = {
|
132
|
+
// intent: {
|
133
|
+
// route: {
|
134
|
+
// calls: [
|
135
|
+
// { target: address1, data: '0x11' },
|
136
|
+
// { target: address2, data: '0x22' },
|
137
|
+
// ],
|
138
|
+
// },
|
139
|
+
// },
|
140
|
+
// } as any
|
141
|
+
// utilsIntentService.getTransactionTargetData = jest
|
142
|
+
// .fn()
|
143
|
+
// .mockImplementation((model, solver, call) => {
|
144
|
+
// if (call.target === address2) return null
|
145
|
+
// return { decoded: true }
|
146
|
+
// })
|
147
|
+
// expect(utilsIntentService.selectorsSupported(model, {} as any)).toBe(false)
|
148
|
+
// })
|
149
|
+
|
150
|
+
// it('should return true when all target transactions decode', async () => {
|
151
|
+
// const model = {
|
152
|
+
// intent: {
|
153
|
+
// route: {
|
154
|
+
// calls: [
|
155
|
+
// { target: address1, data: '0x11' },
|
156
|
+
// { target: address2, data: '0x22' },
|
157
|
+
// ],
|
158
|
+
// },
|
159
|
+
// },
|
160
|
+
// } as any
|
161
|
+
// utilsIntentService.getTransactionTargetData = jest.fn().mockReturnValue({ decoded: true })
|
162
|
+
// expect(utilsIntentService.selectorsSupported(model, {} as any)).toBe(true)
|
163
|
+
// })
|
164
|
+
// })
|
165
|
+
// describe('on targetsSupported', () => {
|
166
|
+
// const target = address1
|
167
|
+
// const target1 = address2
|
168
|
+
// const targetConfig = { contractType: 'erc20', selectors: [] }
|
169
|
+
|
170
|
+
// it('should return false if model targets are empty', async () => {
|
171
|
+
// const model = {
|
172
|
+
// intent: { route: { calls: [] }, hash: '0x9' },
|
173
|
+
// event: { sourceNetwork: 'opt-sepolia' },
|
174
|
+
// } as any
|
175
|
+
// const solver = { targets: { address1: { contractType: 'erc20', selectors: [] } } }
|
176
|
+
// expect(utilsIntentService.supportedTargets(model, solver as any)).toBe(false)
|
177
|
+
// expect(mockLogDebug).toHaveBeenCalledTimes(1)
|
178
|
+
// expect(mockLogDebug).toHaveBeenCalledWith({
|
179
|
+
// msg: `Targets not supported for intent ${model.intent.hash}`,
|
180
|
+
// intentHash: model.intent.hash,
|
181
|
+
// sourceNetwork: model.event.sourceNetwork,
|
182
|
+
// })
|
183
|
+
// })
|
184
|
+
|
185
|
+
// it('should return false if solver targets are empty', async () => {
|
186
|
+
// const model = {
|
187
|
+
// intent: { route: { calls: [{ target, data: '0x' }] }, hash: '0x9' },
|
188
|
+
// event: { sourceNetwork: 'opt-sepolia' },
|
189
|
+
// } as any
|
190
|
+
// const solver = { targets: {} }
|
191
|
+
// expect(utilsIntentService.supportedTargets(model, solver as any)).toBe(false)
|
192
|
+
// expect(mockLogDebug).toHaveBeenCalledTimes(1)
|
193
|
+
// expect(mockLogDebug).toHaveBeenCalledWith({
|
194
|
+
// msg: `Targets not supported for intent ${model.intent.hash}`,
|
195
|
+
// intentHash: model.intent.hash,
|
196
|
+
// sourceNetwork: model.event.sourceNetwork,
|
197
|
+
// })
|
198
|
+
// })
|
199
|
+
|
200
|
+
// it('should return false if solver doesn`t support the targets of the model', async () => {
|
201
|
+
// const model = {
|
202
|
+
// intent: { route: { calls: [{ target, data: '0x' }] }, hash: '0x9' },
|
203
|
+
// event: { sourceNetwork: 'opt-sepolia' },
|
204
|
+
// } as any
|
205
|
+
// const solver = { targets: { [target1]: targetConfig } }
|
206
|
+
// expect(utilsIntentService.supportedTargets(model, solver as any)).toBe(false)
|
207
|
+
// expect(mockLogDebug).toHaveBeenCalledTimes(1)
|
208
|
+
// expect(mockLogDebug).toHaveBeenCalledWith({
|
209
|
+
// msg: `Targets not supported for intent ${model.intent.hash}`,
|
210
|
+
// intentHash: model.intent.hash,
|
211
|
+
// sourceNetwork: model.event.sourceNetwork,
|
212
|
+
// })
|
213
|
+
// })
|
214
|
+
|
215
|
+
// it('should return true if model targets are a subset of solver targets', async () => {
|
216
|
+
// const model = {
|
217
|
+
// intent: { route: { calls: [{ target, data: '0x' }] }, hash: '0x9' },
|
218
|
+
// event: { sourceNetwork: 'opt-sepolia' },
|
219
|
+
// } as any
|
220
|
+
// const solver = { targets: { [target]: targetConfig, [target1]: targetConfig } }
|
221
|
+
// expect(utilsIntentService.supportedTargets(model, solver as any)).toBe(true)
|
222
|
+
// })
|
223
|
+
// })
|
224
|
+
|
225
|
+
describe('on getIntentProcessData', () => {
|
226
|
+
const intentHash = address1
|
227
|
+
const model = {
|
228
|
+
intent: { route: { hash: intentHash, destination: '85432' } },
|
229
|
+
event: { sourceNetwork: 'opt-sepolia' },
|
230
|
+
} as any
|
231
|
+
it('should return undefined if it could not find the model in the db', async () => {
|
232
|
+
intentModel.findOne = jest.fn().mockReturnValue(null)
|
233
|
+
expect(await utilsIntentService.getIntentProcessData(intentHash)).toStrictEqual({
|
234
|
+
err: EcoError.IntentSourceDataNotFound(intentHash),
|
235
|
+
model: null,
|
236
|
+
solver: null,
|
237
|
+
})
|
238
|
+
})
|
239
|
+
|
240
|
+
it('should return undefined if solver could for destination chain could not be found', async () => {
|
241
|
+
intentModel.findOne = jest.fn().mockReturnValue(model)
|
242
|
+
ecoConfigService.getSolver = jest.fn().mockReturnValue(undefined)
|
243
|
+
expect(await utilsIntentService.getIntentProcessData(intentHash)).toBe(undefined)
|
244
|
+
expect(mockLogLog).toHaveBeenCalledTimes(1)
|
245
|
+
expect(mockLogLog).toHaveBeenCalledWith({
|
246
|
+
msg: `No solver found for chain ${model.intent.route.destination}`,
|
247
|
+
intentHash: intentHash,
|
248
|
+
sourceNetwork: model.event.sourceNetwork,
|
249
|
+
})
|
250
|
+
})
|
251
|
+
|
252
|
+
it('should throw an error if model db throws (permissions issue usually)', async () => {
|
253
|
+
const mockLogError = jest.fn()
|
254
|
+
utilsIntentService['logger'].error = mockLogError
|
255
|
+
const err = new Error('DB error')
|
256
|
+
intentModel.findOne = jest.fn().mockRejectedValue(err)
|
257
|
+
expect(await utilsIntentService.getIntentProcessData(intentHash)).toBe(undefined)
|
258
|
+
expect(mockLogError).toHaveBeenCalledTimes(1)
|
259
|
+
expect(mockLogError).toHaveBeenCalledWith({
|
260
|
+
msg: `Error in getIntentProcessData ${intentHash}`,
|
261
|
+
intentHash: intentHash,
|
262
|
+
error: err,
|
263
|
+
})
|
264
|
+
})
|
265
|
+
|
266
|
+
it('should return the model and solver when successful', async () => {
|
267
|
+
intentModel.findOne = jest.fn().mockReturnValue(model)
|
268
|
+
const solver = { chainID: '85432' }
|
269
|
+
ecoConfigService.getSolver = jest.fn().mockReturnValue(solver)
|
270
|
+
expect(await utilsIntentService.getIntentProcessData(intentHash)).toEqual({ model, solver })
|
271
|
+
})
|
272
|
+
})
|
273
|
+
|
274
|
+
describe('on updateOnFulfillment', () => {
|
275
|
+
const fulfillment = {
|
276
|
+
args: {
|
277
|
+
_hash: '0x123',
|
278
|
+
_solver: '0x456',
|
279
|
+
_intent: '0x789',
|
280
|
+
_receipt: '0xabc',
|
281
|
+
_result: '0xdef',
|
282
|
+
},
|
283
|
+
} as any as FulfillmentLog
|
284
|
+
it('should log a warning if no intent exists in the db for the fulfillment hash', async () => {
|
285
|
+
intentModel.findOne = jest.fn().mockReturnValue(undefined)
|
286
|
+
await utilsIntentService.updateOnFulfillment(fulfillment)
|
287
|
+
expect(mockLogWarn).toHaveBeenCalledTimes(1)
|
288
|
+
expect(mockLogWarn).toHaveBeenCalledWith({
|
289
|
+
msg: `Intent not found for fulfillment ${fulfillment.args._hash}`,
|
290
|
+
fulfillment,
|
291
|
+
})
|
292
|
+
})
|
293
|
+
|
294
|
+
it('should update the intent as solved if it exists', async () => {
|
295
|
+
const model = {
|
296
|
+
face: 1,
|
297
|
+
status: 'PENDING',
|
298
|
+
}
|
299
|
+
intentModel.findOne = jest.fn().mockReturnValue(model)
|
300
|
+
await utilsIntentService.updateOnFulfillment(fulfillment)
|
301
|
+
expect(intentModel.updateOne).toHaveBeenCalledTimes(1)
|
302
|
+
expect(intentModel.updateOne).toHaveBeenCalledWith(
|
303
|
+
{ 'intent.hash': fulfillment.args._hash },
|
304
|
+
{ ...model, status: 'SOLVED' },
|
305
|
+
)
|
306
|
+
})
|
307
|
+
})
|
308
|
+
})
|
@@ -0,0 +1,62 @@
|
|
1
|
+
const mockDecodeFunctionData = jest.fn()
|
2
|
+
import { EcoError } from '@/common/errors/eco-error'
|
3
|
+
import { getFunctionBytes } from '@/common/viem/contracts'
|
4
|
+
import { CallDataInterface } from '@/contracts'
|
5
|
+
import { getTransactionTargetData } from '@/intent/utils'
|
6
|
+
|
7
|
+
jest.mock('viem', () => {
|
8
|
+
return {
|
9
|
+
...jest.requireActual('viem'),
|
10
|
+
decodeFunctionData: mockDecodeFunctionData,
|
11
|
+
}
|
12
|
+
})
|
13
|
+
|
14
|
+
const address1 = '0x1111111111111111111111111111111111111111'
|
15
|
+
describe('utils tests', () => {
|
16
|
+
describe('on getTransactionTargetData', () => {
|
17
|
+
const callData: CallDataInterface = { target: address1, data: '0xa9059cbb3333333', value: 0n } //transfer selector plus data fake
|
18
|
+
const selectors = ['transfer(address,uint256)']
|
19
|
+
const targetConfig = { contractType: 'erc20', selectors }
|
20
|
+
const decodedData = { stuff: true }
|
21
|
+
|
22
|
+
it('should throw when no target config exists on solver', async () => {
|
23
|
+
const solver = { targets: {} }
|
24
|
+
expect(() => getTransactionTargetData(solver as any, callData)).toThrow(
|
25
|
+
EcoError.IntentSourceTargetConfigNotFound(callData.target as string),
|
26
|
+
)
|
27
|
+
})
|
28
|
+
|
29
|
+
it('should return null when tx is not decoded ', async () => {
|
30
|
+
mockDecodeFunctionData.mockReturnValue(null)
|
31
|
+
expect(
|
32
|
+
getTransactionTargetData(
|
33
|
+
{ targets: { [address1]: { contractType: 'erc20', selectors } } } as any,
|
34
|
+
callData,
|
35
|
+
),
|
36
|
+
).toBe(null)
|
37
|
+
})
|
38
|
+
|
39
|
+
it('should return null when target selector is not supported by the solver', async () => {
|
40
|
+
const fakeData = '0xaaaaaaaa11112333'
|
41
|
+
const call: CallDataInterface = { target: callData.target, data: fakeData, value: 0n }
|
42
|
+
mockDecodeFunctionData.mockReturnValue(decodedData)
|
43
|
+
expect(
|
44
|
+
getTransactionTargetData(
|
45
|
+
{ targets: { [address1]: { contractType: 'erc20', selectors } } } as any,
|
46
|
+
call,
|
47
|
+
),
|
48
|
+
).toBe(null)
|
49
|
+
})
|
50
|
+
|
51
|
+
it('should return the decoded function data, selctor and target config when successful', async () => {
|
52
|
+
mockDecodeFunctionData.mockReturnValue(decodedData)
|
53
|
+
expect(
|
54
|
+
getTransactionTargetData({ targets: { [address1]: targetConfig } } as any, callData),
|
55
|
+
).toEqual({
|
56
|
+
decodedFunctionData: decodedData,
|
57
|
+
selector: getFunctionBytes(callData.data),
|
58
|
+
targetConfig,
|
59
|
+
})
|
60
|
+
})
|
61
|
+
})
|
62
|
+
})
|
@@ -0,0 +1,297 @@
|
|
1
|
+
const mockGetIntentJobId = jest.fn()
|
2
|
+
import { createMock, DeepMocked } from '@golevelup/ts-jest'
|
3
|
+
import { EcoConfigService } from '../../eco-configs/eco-config.service'
|
4
|
+
import { Test, TestingModule } from '@nestjs/testing'
|
5
|
+
import { getModelToken } from '@nestjs/mongoose'
|
6
|
+
import { IntentSourceModel } from '../schemas/intent-source.schema'
|
7
|
+
import { Model } from 'mongoose'
|
8
|
+
import { ValidateIntentService } from '../validate-intent.service'
|
9
|
+
import { UtilsIntentService } from '../utils-intent.service'
|
10
|
+
import { BullModule, getQueueToken } from '@nestjs/bullmq'
|
11
|
+
import { QUEUES } from '../../common/redis/constants'
|
12
|
+
import { Queue } from 'bullmq'
|
13
|
+
import { ValidationService } from '@/intent/validation.sevice'
|
14
|
+
import { zeroHash } from 'viem'
|
15
|
+
import { MultichainPublicClientService } from '@/transaction/multichain-public-client.service'
|
16
|
+
import { EcoError } from '@/common/errors/eco-error'
|
17
|
+
|
18
|
+
jest.mock('../../common/utils/strings', () => {
|
19
|
+
return {
|
20
|
+
...jest.requireActual('../../common/utils/strings'),
|
21
|
+
getIntentJobId: mockGetIntentJobId,
|
22
|
+
}
|
23
|
+
})
|
24
|
+
|
25
|
+
describe('ValidateIntentService', () => {
|
26
|
+
let validateIntentService: ValidateIntentService
|
27
|
+
let validationService: DeepMocked<ValidationService>
|
28
|
+
let multichainPublicClientService: DeepMocked<MultichainPublicClientService>
|
29
|
+
let utilsIntentService: DeepMocked<UtilsIntentService>
|
30
|
+
let ecoConfigService: DeepMocked<EcoConfigService>
|
31
|
+
let queue: DeepMocked<Queue>
|
32
|
+
const mockLogDebug = jest.fn()
|
33
|
+
const mockLog = jest.fn()
|
34
|
+
const mockLogError = jest.fn()
|
35
|
+
|
36
|
+
beforeEach(async () => {
|
37
|
+
const chainMod: TestingModule = await Test.createTestingModule({
|
38
|
+
providers: [
|
39
|
+
ValidateIntentService,
|
40
|
+
{
|
41
|
+
provide: UtilsIntentService,
|
42
|
+
useValue: createMock<UtilsIntentService>(),
|
43
|
+
},
|
44
|
+
{ provide: ValidationService, useValue: createMock<ValidationService>() },
|
45
|
+
{
|
46
|
+
provide: MultichainPublicClientService,
|
47
|
+
useValue: createMock<MultichainPublicClientService>(),
|
48
|
+
},
|
49
|
+
{ provide: UtilsIntentService, useValue: createMock<UtilsIntentService>() },
|
50
|
+
{ provide: EcoConfigService, useValue: createMock<EcoConfigService>() },
|
51
|
+
{
|
52
|
+
provide: getModelToken(IntentSourceModel.name),
|
53
|
+
useValue: createMock<Model<IntentSourceModel>>(),
|
54
|
+
},
|
55
|
+
],
|
56
|
+
imports: [
|
57
|
+
BullModule.registerQueue({
|
58
|
+
name: QUEUES.SOURCE_INTENT.queue,
|
59
|
+
}),
|
60
|
+
],
|
61
|
+
})
|
62
|
+
.overrideProvider(getQueueToken(QUEUES.SOURCE_INTENT.queue))
|
63
|
+
.useValue(createMock<Queue>())
|
64
|
+
.compile()
|
65
|
+
|
66
|
+
validateIntentService = chainMod.get(ValidateIntentService)
|
67
|
+
validationService = chainMod.get(ValidationService)
|
68
|
+
multichainPublicClientService = chainMod.get(MultichainPublicClientService)
|
69
|
+
utilsIntentService = chainMod.get(UtilsIntentService)
|
70
|
+
ecoConfigService = chainMod.get(EcoConfigService)
|
71
|
+
queue = chainMod.get(getQueueToken(QUEUES.SOURCE_INTENT.queue))
|
72
|
+
|
73
|
+
validateIntentService['logger'].debug = mockLogDebug
|
74
|
+
validateIntentService['logger'].log = mockLog
|
75
|
+
validateIntentService['logger'].error = mockLogError
|
76
|
+
})
|
77
|
+
|
78
|
+
afterEach(async () => {
|
79
|
+
// restore the spy created with spyOn
|
80
|
+
jest.resetAllMocks()
|
81
|
+
})
|
82
|
+
|
83
|
+
describe('on module init', () => {
|
84
|
+
it('should set the intentJobConfig', () => {
|
85
|
+
const config = { a: 1 } as any
|
86
|
+
ecoConfigService.getRedis = jest
|
87
|
+
.fn()
|
88
|
+
.mockReturnValueOnce({ jobs: { intentJobConfig: config } })
|
89
|
+
validateIntentService.onModuleInit()
|
90
|
+
expect(validateIntentService['intentJobConfig']).toEqual(config)
|
91
|
+
})
|
92
|
+
})
|
93
|
+
|
94
|
+
describe('on destructureIntent', () => {
|
95
|
+
it('should throw if get intent returns no data', async () => {
|
96
|
+
utilsIntentService.getIntentProcessData.mockResolvedValueOnce(undefined)
|
97
|
+
await expect(validateIntentService['destructureIntent'](zeroHash)).rejects.toThrow(
|
98
|
+
'Desctructuring the intent from the intent hash failed',
|
99
|
+
)
|
100
|
+
})
|
101
|
+
|
102
|
+
it('should throw if solver is undefined', async () => {
|
103
|
+
utilsIntentService.getIntentProcessData.mockResolvedValueOnce({ model: {} } as any)
|
104
|
+
await expect(validateIntentService['destructureIntent'](zeroHash)).rejects.toThrow(
|
105
|
+
'Desctructuring the intent from the intent hash failed',
|
106
|
+
)
|
107
|
+
})
|
108
|
+
|
109
|
+
it('should throw if model is undefined', async () => {
|
110
|
+
utilsIntentService.getIntentProcessData.mockResolvedValueOnce({ solver: {} } as any)
|
111
|
+
await expect(validateIntentService['destructureIntent'](zeroHash)).rejects.toThrow(
|
112
|
+
'Desctructuring the intent from the intent hash failed',
|
113
|
+
)
|
114
|
+
})
|
115
|
+
|
116
|
+
it('should throw error if its returned', async () => {
|
117
|
+
const msg = 'Error from getIntentProcessData'
|
118
|
+
utilsIntentService.getIntentProcessData.mockResolvedValueOnce({
|
119
|
+
err: new Error(msg),
|
120
|
+
} as any)
|
121
|
+
await expect(validateIntentService['destructureIntent'](zeroHash)).rejects.toThrow('Error')
|
122
|
+
})
|
123
|
+
|
124
|
+
it('should throw generic error if no error returned', async () => {
|
125
|
+
utilsIntentService.getIntentProcessData.mockResolvedValueOnce({} as any)
|
126
|
+
await expect(validateIntentService['destructureIntent'](zeroHash)).rejects.toThrow(
|
127
|
+
'Desctructuring the intent from the intent hash failed',
|
128
|
+
)
|
129
|
+
})
|
130
|
+
|
131
|
+
it('should succeed and return data', async () => {
|
132
|
+
const dataIn = { model: {}, solver: {} } as any
|
133
|
+
utilsIntentService.getIntentProcessData.mockResolvedValueOnce(dataIn)
|
134
|
+
const dataOut = await validateIntentService['destructureIntent'](zeroHash)
|
135
|
+
expect(dataOut).toBe(dataIn)
|
136
|
+
})
|
137
|
+
})
|
138
|
+
|
139
|
+
describe('on validateIntent entrypoint', () => {
|
140
|
+
it('should log when entering function and return on failed destructure', async () => {
|
141
|
+
const intentHash = '0x1'
|
142
|
+
validateIntentService['destructureIntent'] = jest
|
143
|
+
.fn()
|
144
|
+
.mockReturnValueOnce({ model: undefined, solver: undefined })
|
145
|
+
expect(await validateIntentService.validateIntent(intentHash)).toBe(false)
|
146
|
+
expect(mockLogDebug).toHaveBeenCalledTimes(1)
|
147
|
+
expect(mockLogDebug).toHaveBeenCalledWith({ msg: `validateIntent ${intentHash}`, intentHash })
|
148
|
+
})
|
149
|
+
|
150
|
+
it('should return on failed assertions', async () => {
|
151
|
+
const intentHash = '0x1'
|
152
|
+
validateIntentService['destructureIntent'] = jest
|
153
|
+
.fn()
|
154
|
+
.mockReturnValueOnce({ model: {}, solver: {} })
|
155
|
+
validateIntentService['assertValidations'] = jest.fn().mockReturnValueOnce(false)
|
156
|
+
expect(await validateIntentService.validateIntent(intentHash)).toBe(false)
|
157
|
+
expect(mockLogDebug).toHaveBeenCalledTimes(1)
|
158
|
+
})
|
159
|
+
|
160
|
+
it('should log, create a job and enque it', async () => {
|
161
|
+
const intentHash = '0x1'
|
162
|
+
const model = { intent: { logIndex: 10 } }
|
163
|
+
const config = { a: 1 } as any
|
164
|
+
validateIntentService['destructureIntent'] = jest
|
165
|
+
.fn()
|
166
|
+
.mockReturnValueOnce({ model, solver: {} })
|
167
|
+
validateIntentService['assertValidations'] = jest.fn().mockReturnValueOnce(true)
|
168
|
+
validateIntentService['intentJobConfig'] = config
|
169
|
+
const mockAddQueue = jest.fn()
|
170
|
+
queue.add = mockAddQueue
|
171
|
+
const jobId = 'validate-asdf-0'
|
172
|
+
mockGetIntentJobId.mockReturnValueOnce(jobId)
|
173
|
+
expect(await validateIntentService.validateIntent(intentHash)).toBe(true)
|
174
|
+
expect(mockGetIntentJobId).toHaveBeenCalledTimes(1)
|
175
|
+
expect(mockAddQueue).toHaveBeenCalledTimes(1)
|
176
|
+
expect(mockLogDebug).toHaveBeenCalledTimes(2)
|
177
|
+
expect(mockGetIntentJobId).toHaveBeenCalledWith('validate', intentHash, model.intent.logIndex)
|
178
|
+
expect(mockAddQueue).toHaveBeenCalledWith(
|
179
|
+
QUEUES.SOURCE_INTENT.jobs.feasable_intent,
|
180
|
+
intentHash,
|
181
|
+
{
|
182
|
+
jobId,
|
183
|
+
...validateIntentService['intentJobConfig'],
|
184
|
+
},
|
185
|
+
)
|
186
|
+
expect(mockLogDebug).toHaveBeenCalledWith({
|
187
|
+
msg: `validateIntent ${intentHash}`,
|
188
|
+
intentHash,
|
189
|
+
jobId,
|
190
|
+
})
|
191
|
+
})
|
192
|
+
})
|
193
|
+
|
194
|
+
describe('on assertValidations', () => {
|
195
|
+
const model = { intent: { hash: '0x12' } } as any
|
196
|
+
const solver = {} as any
|
197
|
+
const validations = { isIntentFunded: false, supportedSelectors: true } as any
|
198
|
+
const validValidations = { isIntentFunded: true, supportedSelectors: true } as any
|
199
|
+
let mockValidations: jest.Mock
|
200
|
+
let mockIntentFunded: jest.Mock
|
201
|
+
let mockUpdateModel: jest.Mock
|
202
|
+
|
203
|
+
beforeEach(() => {
|
204
|
+
mockValidations = jest.fn().mockResolvedValueOnce(validations)
|
205
|
+
mockIntentFunded = jest.fn().mockResolvedValueOnce(true)
|
206
|
+
mockUpdateModel = jest.fn()
|
207
|
+
|
208
|
+
validationService.assertValidations = mockValidations
|
209
|
+
validateIntentService.intentFunded = mockIntentFunded
|
210
|
+
utilsIntentService.updateInvalidIntentModel = mockUpdateModel
|
211
|
+
})
|
212
|
+
|
213
|
+
it('should return false if ValidationService is false', async () => {
|
214
|
+
expect(await validateIntentService.assertValidations(model, solver)).toBe(false)
|
215
|
+
expect(mockValidations).toHaveBeenCalledTimes(1)
|
216
|
+
expect(mockIntentFunded).toHaveBeenCalledTimes(1)
|
217
|
+
expect(mockUpdateModel).toHaveBeenCalledTimes(1)
|
218
|
+
expect(mockLog).toHaveBeenCalledTimes(1)
|
219
|
+
expect(mockLog).toHaveBeenCalledWith({
|
220
|
+
msg: EcoError.IntentValidationFailed(model.intent.hash).message,
|
221
|
+
model,
|
222
|
+
validations,
|
223
|
+
})
|
224
|
+
expect(mockUpdateModel).toHaveBeenCalledWith(model, validations)
|
225
|
+
})
|
226
|
+
|
227
|
+
it('should return false if intentFunded returns false', async () => {
|
228
|
+
mockValidations = jest.fn().mockResolvedValueOnce(validValidations)
|
229
|
+
mockIntentFunded = jest.fn().mockResolvedValueOnce(false)
|
230
|
+
validationService.assertValidations = mockValidations
|
231
|
+
validateIntentService.intentFunded = mockIntentFunded
|
232
|
+
|
233
|
+
expect(await validateIntentService.assertValidations(model, solver)).toBe(false)
|
234
|
+
expect(mockValidations).toHaveBeenCalledTimes(1)
|
235
|
+
expect(mockIntentFunded).toHaveBeenCalledTimes(1)
|
236
|
+
expect(mockUpdateModel).toHaveBeenCalledTimes(1)
|
237
|
+
expect(mockLog).toHaveBeenCalledTimes(1)
|
238
|
+
expect(mockLog).toHaveBeenCalledWith({
|
239
|
+
msg: EcoError.IntentValidationFailed(model.intent.hash).message,
|
240
|
+
model,
|
241
|
+
validations: validValidations,
|
242
|
+
})
|
243
|
+
expect(mockUpdateModel).toHaveBeenCalledWith(model, validValidations)
|
244
|
+
})
|
245
|
+
|
246
|
+
it('should return true if intentFunded and ValidationService are all true ', async () => {
|
247
|
+
mockValidations = jest.fn().mockResolvedValueOnce(validValidations)
|
248
|
+
mockIntentFunded = jest.fn().mockResolvedValueOnce(true)
|
249
|
+
validationService.assertValidations = mockValidations
|
250
|
+
validateIntentService.intentFunded = mockIntentFunded
|
251
|
+
|
252
|
+
expect(await validateIntentService.assertValidations(model, solver)).toBe(true)
|
253
|
+
expect(mockValidations).toHaveBeenCalledTimes(1)
|
254
|
+
expect(mockIntentFunded).toHaveBeenCalledTimes(1)
|
255
|
+
expect(mockUpdateModel).toHaveBeenCalledTimes(0)
|
256
|
+
expect(mockLog).toHaveBeenCalledTimes(0)
|
257
|
+
})
|
258
|
+
})
|
259
|
+
|
260
|
+
describe('on intentFunded', () => {
|
261
|
+
const chainID = 1
|
262
|
+
const model = { intent: { hash: '0x12', route: { source: chainID } } } as any
|
263
|
+
|
264
|
+
it('should return false if no intentSource for intent', async () => {
|
265
|
+
jest.spyOn(ecoConfigService, 'getIntentSource').mockReturnValue(undefined)
|
266
|
+
|
267
|
+
expect(await validateIntentService.intentFunded(model)).toBe(false)
|
268
|
+
expect(mockLogError).toHaveBeenCalledTimes(1)
|
269
|
+
expect(mockLogError).toHaveBeenCalledWith({
|
270
|
+
msg: EcoError.IntentSourceNotFound(chainID).message,
|
271
|
+
model,
|
272
|
+
})
|
273
|
+
})
|
274
|
+
|
275
|
+
it('should return false if isIntentFunded contract call returns false', async () => {
|
276
|
+
jest.spyOn(ecoConfigService, 'getIntentSource').mockReturnValue({ face: 'face' } as any)
|
277
|
+
const mockRead = jest.fn().mockReturnValue(false)
|
278
|
+
const client = { readContract: mockRead }
|
279
|
+
multichainPublicClientService.getClient = jest.fn().mockReturnValue(client)
|
280
|
+
|
281
|
+
expect(await validateIntentService.intentFunded(model)).toBe(false)
|
282
|
+
expect(mockLogError).toHaveBeenCalledTimes(0)
|
283
|
+
expect(mockRead).toHaveBeenCalledTimes(1)
|
284
|
+
})
|
285
|
+
|
286
|
+
it('should return true if isIntentFunded contract call returns true', async () => {
|
287
|
+
jest.spyOn(ecoConfigService, 'getIntentSource').mockReturnValue({ face: 'face' } as any)
|
288
|
+
const mockRead = jest.fn().mockReturnValue(true)
|
289
|
+
const client = { readContract: mockRead }
|
290
|
+
multichainPublicClientService.getClient = jest.fn().mockReturnValue(client)
|
291
|
+
|
292
|
+
expect(await validateIntentService.intentFunded(model)).toBe(true)
|
293
|
+
expect(mockLogError).toHaveBeenCalledTimes(0)
|
294
|
+
expect(mockRead).toHaveBeenCalledTimes(1)
|
295
|
+
})
|
296
|
+
})
|
297
|
+
})
|