eco-solver 0.0.1-security → 1.5.1
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 +115 -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,176 @@
|
|
1
|
+
import { Injectable, Logger, OnModuleInit } from '@nestjs/common'
|
2
|
+
import { EcoConfigService } from '../eco-configs/eco-config.service'
|
3
|
+
import { EcoLogMessage } from '../common/logging/eco-log-message'
|
4
|
+
import { IntentProcessData, UtilsIntentService } from './utils-intent.service'
|
5
|
+
import { QUEUES } from '../common/redis/constants'
|
6
|
+
import { JobsOptions, Queue } from 'bullmq'
|
7
|
+
import { InjectQueue } from '@nestjs/bullmq'
|
8
|
+
import { getIntentJobId } from '../common/utils/strings'
|
9
|
+
import { Solver } from '../eco-configs/eco-config.types'
|
10
|
+
import { IntentSourceModel } from './schemas/intent-source.schema'
|
11
|
+
import { Hex } from 'viem'
|
12
|
+
import { EcoError } from '../common/errors/eco-error'
|
13
|
+
import { ValidationChecks, ValidationService, validationsFailed } from '@/intent/validation.sevice'
|
14
|
+
import { MultichainPublicClientService } from '@/transaction/multichain-public-client.service'
|
15
|
+
import { IntentSourceAbi } from '@eco-foundation/routes-ts'
|
16
|
+
import { IntentDataModel } from '@/intent/schemas/intent-data.schema'
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Type that merges the {@link ValidationChecks} with the intentFunded check
|
20
|
+
*/
|
21
|
+
export type IntentValidations = ValidationChecks & {
|
22
|
+
intentFunded: boolean
|
23
|
+
}
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Service class that acts as the main validation service for intents.
|
27
|
+
* Validation {@license ValidationService}:
|
28
|
+
* 1. Supports the prover
|
29
|
+
* 2. Supports the targets
|
30
|
+
* 3. Supports the selectors
|
31
|
+
* 4. Has a valid transfer limit
|
32
|
+
* 5. Has a valid expiration time
|
33
|
+
* 6. Fulfill chain not same as source chain
|
34
|
+
*
|
35
|
+
* Validates that the intent was also funded:
|
36
|
+
* 1. The intent was funded on chain in the IntentSource
|
37
|
+
*
|
38
|
+
* As well as some structural checks on the intent model
|
39
|
+
*/
|
40
|
+
@Injectable()
|
41
|
+
export class ValidateIntentService implements OnModuleInit {
|
42
|
+
private logger = new Logger(ValidateIntentService.name)
|
43
|
+
private intentJobConfig: JobsOptions
|
44
|
+
|
45
|
+
constructor(
|
46
|
+
@InjectQueue(QUEUES.SOURCE_INTENT.queue) private readonly intentQueue: Queue,
|
47
|
+
private readonly validationService: ValidationService,
|
48
|
+
private readonly multichainPublicClientService: MultichainPublicClientService,
|
49
|
+
private readonly utilsIntentService: UtilsIntentService,
|
50
|
+
private readonly ecoConfigService: EcoConfigService,
|
51
|
+
) {}
|
52
|
+
|
53
|
+
onModuleInit() {
|
54
|
+
this.intentJobConfig = this.ecoConfigService.getRedis().jobs.intentJobConfig
|
55
|
+
}
|
56
|
+
|
57
|
+
/**
|
58
|
+
* @param intentHash the hash of the intent to fulfill
|
59
|
+
*/
|
60
|
+
async validateIntent(intentHash: Hex) {
|
61
|
+
this.logger.debug(
|
62
|
+
EcoLogMessage.fromDefault({
|
63
|
+
message: `validateIntent ${intentHash}`,
|
64
|
+
properties: {
|
65
|
+
intentHash: intentHash,
|
66
|
+
},
|
67
|
+
}),
|
68
|
+
)
|
69
|
+
|
70
|
+
const { model, solver } = await this.destructureIntent(intentHash)
|
71
|
+
if (!model || !solver) {
|
72
|
+
return false
|
73
|
+
}
|
74
|
+
|
75
|
+
if (!(await this.assertValidations(model, solver))) {
|
76
|
+
return false
|
77
|
+
}
|
78
|
+
|
79
|
+
const jobId = getIntentJobId('validate', intentHash, model.intent.logIndex)
|
80
|
+
this.logger.debug(
|
81
|
+
EcoLogMessage.fromDefault({
|
82
|
+
message: `validateIntent ${intentHash}`,
|
83
|
+
properties: {
|
84
|
+
intentHash,
|
85
|
+
jobId,
|
86
|
+
},
|
87
|
+
}),
|
88
|
+
)
|
89
|
+
//add to processing queue
|
90
|
+
await this.intentQueue.add(QUEUES.SOURCE_INTENT.jobs.feasable_intent, intentHash, {
|
91
|
+
jobId,
|
92
|
+
...this.intentJobConfig,
|
93
|
+
})
|
94
|
+
|
95
|
+
return true
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Executes all the validations we have on the model and solver
|
100
|
+
*
|
101
|
+
* @param model the source intent model
|
102
|
+
* @param solver the solver for the source chain
|
103
|
+
* @returns true if they all pass, false otherwise
|
104
|
+
*/
|
105
|
+
async assertValidations(model: IntentSourceModel, solver: Solver): Promise<boolean> {
|
106
|
+
const validations = (await this.validationService.assertValidations(
|
107
|
+
model.intent,
|
108
|
+
solver,
|
109
|
+
)) as IntentValidations
|
110
|
+
validations.intentFunded = await this.intentFunded(model)
|
111
|
+
|
112
|
+
if (validationsFailed(validations)) {
|
113
|
+
await this.utilsIntentService.updateInvalidIntentModel(model, validations)
|
114
|
+
this.logger.log(
|
115
|
+
EcoLogMessage.fromDefault({
|
116
|
+
message: EcoError.IntentValidationFailed(model.intent.hash).message,
|
117
|
+
properties: {
|
118
|
+
model,
|
119
|
+
validations,
|
120
|
+
},
|
121
|
+
}),
|
122
|
+
)
|
123
|
+
return false
|
124
|
+
}
|
125
|
+
|
126
|
+
return true
|
127
|
+
}
|
128
|
+
|
129
|
+
/**
|
130
|
+
* Makes on onchain read call to make sure that the intent was funded in the IntentSource
|
131
|
+
* contract.
|
132
|
+
* @Notice An event emitted is not enough to guarantee that the intent was funded
|
133
|
+
* @param model the source intent model
|
134
|
+
* @returns
|
135
|
+
*/
|
136
|
+
async intentFunded(model: IntentSourceModel): Promise<boolean> {
|
137
|
+
const sourceChainID = Number(model.intent.route.source)
|
138
|
+
const client = await this.multichainPublicClientService.getClient(sourceChainID)
|
139
|
+
const intentSource = this.ecoConfigService.getIntentSource(sourceChainID)
|
140
|
+
if (!intentSource) {
|
141
|
+
this.logger.error(
|
142
|
+
EcoLogMessage.fromDefault({
|
143
|
+
message: EcoError.IntentSourceNotFound(sourceChainID).message,
|
144
|
+
properties: {
|
145
|
+
model,
|
146
|
+
},
|
147
|
+
}),
|
148
|
+
)
|
149
|
+
return false
|
150
|
+
}
|
151
|
+
|
152
|
+
const isIntentFunded = await client.readContract({
|
153
|
+
address: intentSource.sourceAddress,
|
154
|
+
abi: IntentSourceAbi,
|
155
|
+
functionName: 'isIntentFunded',
|
156
|
+
args: [IntentDataModel.toChainIntent(model.intent)],
|
157
|
+
})
|
158
|
+
return isIntentFunded
|
159
|
+
}
|
160
|
+
|
161
|
+
/**
|
162
|
+
* Fetches the intent from the db and its solver and model from configs. Validates
|
163
|
+
* that both are returned without any error
|
164
|
+
*
|
165
|
+
* @param intentHash the hash of the intent to find in the db
|
166
|
+
* @returns
|
167
|
+
*/
|
168
|
+
private async destructureIntent(intentHash: Hex): Promise<IntentProcessData> {
|
169
|
+
const data = await this.utilsIntentService.getIntentProcessData(intentHash)
|
170
|
+
const { model, solver, err } = data ?? {}
|
171
|
+
if (!data || !model || !solver) {
|
172
|
+
throw EcoError.ValidateIntentDescructureFailed(err)
|
173
|
+
}
|
174
|
+
return data
|
175
|
+
}
|
176
|
+
}
|
@@ -0,0 +1,223 @@
|
|
1
|
+
import { EcoLogMessage } from '@/common/logging/eco-log-message'
|
2
|
+
import { EcoConfigService } from '@/eco-configs/eco-config.service'
|
3
|
+
import { Solver } from '@/eco-configs/eco-config.types'
|
4
|
+
import { FeeService } from '@/fee/fee.service'
|
5
|
+
import { getTransactionTargetData } from '@/intent/utils'
|
6
|
+
import { ProofService } from '@/prover/proof.service'
|
7
|
+
import { QuoteIntentDataInterface } from '@/quote/dto/quote.intent.data.dto'
|
8
|
+
import { Injectable, Logger } from '@nestjs/common'
|
9
|
+
import { difference } from 'lodash'
|
10
|
+
import { Hex } from 'viem'
|
11
|
+
|
12
|
+
interface IntentModelWithHashInterface {
|
13
|
+
hash?: Hex
|
14
|
+
}
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Validation type that mixes the QuoteIntentDataDTO with the hash. This is used to
|
18
|
+
* merge quotes and intents validations
|
19
|
+
*/
|
20
|
+
export interface ValidationIntentInterface
|
21
|
+
extends QuoteIntentDataInterface,
|
22
|
+
IntentModelWithHashInterface {}
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Type that holds all the possible validations that can fail
|
26
|
+
*/
|
27
|
+
export type ValidationChecks = {
|
28
|
+
supportedProver: boolean
|
29
|
+
supportedTargets: boolean
|
30
|
+
supportedSelectors: boolean
|
31
|
+
validTransferLimit: boolean
|
32
|
+
validExpirationTime: boolean
|
33
|
+
validDestination: boolean
|
34
|
+
fulfillOnDifferentChain: boolean
|
35
|
+
}
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Validates that all of the validations succeeded
|
39
|
+
* @param validations the validations to check
|
40
|
+
* @returns true if all of the validations passed
|
41
|
+
*/
|
42
|
+
export function validationsSucceeded(validations: ValidationType): boolean {
|
43
|
+
return Object.values(validations).every((v) => v)
|
44
|
+
}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Checks that at least one of the validations failed
|
48
|
+
* @param validations the validations to check
|
49
|
+
* @returns true if any of the validations failed
|
50
|
+
*/
|
51
|
+
export function validationsFailed(validations: ValidationType): boolean {
|
52
|
+
return !validationsSucceeded(validations)
|
53
|
+
}
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Type that holds all the possible validations that can fail
|
57
|
+
*/
|
58
|
+
export type ValidationType = {
|
59
|
+
[key: string]: boolean
|
60
|
+
}
|
61
|
+
|
62
|
+
@Injectable()
|
63
|
+
export class ValidationService {
|
64
|
+
private readonly logger = new Logger(ValidationService.name)
|
65
|
+
|
66
|
+
constructor(
|
67
|
+
private readonly proofService: ProofService,
|
68
|
+
private readonly feeService: FeeService,
|
69
|
+
private readonly ecoConfigService: EcoConfigService,
|
70
|
+
) {}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Executes all the validations we have on the model and solver
|
74
|
+
*
|
75
|
+
* @param intent the source intent model
|
76
|
+
* @param solver the solver for the source chain
|
77
|
+
* @returns true if they all pass, false otherwise
|
78
|
+
*/
|
79
|
+
async assertValidations(
|
80
|
+
intent: ValidationIntentInterface,
|
81
|
+
solver: Solver,
|
82
|
+
): Promise<ValidationChecks> {
|
83
|
+
const supportedProver = this.supportedProver({
|
84
|
+
sourceChainID: intent.route.source,
|
85
|
+
prover: intent.reward.prover,
|
86
|
+
})
|
87
|
+
const supportedTargets = this.supportedTargets(intent, solver)
|
88
|
+
const supportedSelectors = this.supportedSelectors(intent, solver)
|
89
|
+
const validTransferLimit = await this.validTransferLimit(intent)
|
90
|
+
const validExpirationTime = this.validExpirationTime(intent)
|
91
|
+
const validDestination = this.validDestination(intent)
|
92
|
+
const fulfillOnDifferentChain = this.fulfillOnDifferentChain(intent)
|
93
|
+
|
94
|
+
return {
|
95
|
+
supportedProver,
|
96
|
+
supportedTargets,
|
97
|
+
supportedSelectors,
|
98
|
+
validTransferLimit,
|
99
|
+
validExpirationTime,
|
100
|
+
validDestination,
|
101
|
+
fulfillOnDifferentChain,
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
/**
|
106
|
+
* Checks if the IntentCreated event is using a supported prover. It first finds the source intent contract that is on the
|
107
|
+
* source chain of the event. Then it checks if the prover is supported by the source intent. In the
|
108
|
+
* case that there are multiple matching source intent contracts on the same chain, as long as any of
|
109
|
+
* them support the prover, the function will return true.
|
110
|
+
*
|
111
|
+
* @param ops the intent info
|
112
|
+
* @returns
|
113
|
+
*/
|
114
|
+
supportedProver(ops: { sourceChainID: bigint; prover: Hex }): boolean {
|
115
|
+
const srcSolvers = this.ecoConfigService.getIntentSources().filter((intent) => {
|
116
|
+
return BigInt(intent.chainID) == ops.sourceChainID
|
117
|
+
})
|
118
|
+
|
119
|
+
return srcSolvers.some((intent) => {
|
120
|
+
return intent.provers.some((prover) => prover == ops.prover)
|
121
|
+
})
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Verifies that the intent targets and data arrays are equal in length, and
|
126
|
+
* that every target-data can be decoded
|
127
|
+
*
|
128
|
+
* @param intent the intent model
|
129
|
+
* @param solver the solver for the intent
|
130
|
+
* @returns
|
131
|
+
*/
|
132
|
+
supportedSelectors(intent: ValidationIntentInterface, solver: Solver): boolean {
|
133
|
+
if (intent.route.calls.length == 0) {
|
134
|
+
this.logger.log(
|
135
|
+
EcoLogMessage.fromDefault({
|
136
|
+
message: `supportedSelectors: Target/data invalid`,
|
137
|
+
}),
|
138
|
+
)
|
139
|
+
return false
|
140
|
+
}
|
141
|
+
return intent.route.calls.every((call) => {
|
142
|
+
const tx = getTransactionTargetData(solver, call)
|
143
|
+
return tx
|
144
|
+
})
|
145
|
+
}
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Verifies that all the intent targets are supported by the solver
|
149
|
+
*
|
150
|
+
* @param intent the intent model
|
151
|
+
* @param solver the solver for the intent
|
152
|
+
* @returns
|
153
|
+
*/
|
154
|
+
supportedTargets(intent: ValidationIntentInterface, solver: Solver): boolean {
|
155
|
+
const intentTargets = intent.route.calls.map((call) => call.target)
|
156
|
+
const solverTargets = Object.keys(solver.targets)
|
157
|
+
//all targets are included in the solver targets array
|
158
|
+
const exist = solverTargets.length > 0 && intentTargets.length > 0
|
159
|
+
const targetsSupported = exist && difference(intentTargets, solverTargets).length == 0
|
160
|
+
|
161
|
+
if (!targetsSupported) {
|
162
|
+
this.logger.debug(
|
163
|
+
EcoLogMessage.fromDefault({
|
164
|
+
message: `Targets not supported for intent ${intent.hash ? intent.hash : 'quote'}`,
|
165
|
+
properties: {
|
166
|
+
...(intent.hash && {
|
167
|
+
intentHash: intent.hash,
|
168
|
+
source: intent.route.source,
|
169
|
+
}),
|
170
|
+
},
|
171
|
+
}),
|
172
|
+
)
|
173
|
+
}
|
174
|
+
return targetsSupported
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Checks if the transfer total is within the bounds of the solver, ie below a certain threshold
|
179
|
+
* @param intent the source intent model
|
180
|
+
* @returns true if the transfer is within the bounds
|
181
|
+
*/
|
182
|
+
async validTransferLimit(intent: ValidationIntentInterface): Promise<boolean> {
|
183
|
+
const { totalFillNormalized, error } = await this.feeService.getTotalFill(intent)
|
184
|
+
if (error) {
|
185
|
+
return false
|
186
|
+
}
|
187
|
+
const limitFillBase6 = this.feeService.getFeeConfig({ intent }).limitFillBase6
|
188
|
+
return totalFillNormalized <= limitFillBase6
|
189
|
+
}
|
190
|
+
|
191
|
+
/**
|
192
|
+
*
|
193
|
+
* @param intent the source intent model
|
194
|
+
* @param solver the solver for the source chain
|
195
|
+
* @returns
|
196
|
+
*/
|
197
|
+
validExpirationTime(intent: ValidationIntentInterface): boolean {
|
198
|
+
//convert to milliseconds
|
199
|
+
const time = Number.parseInt(`${intent.reward.deadline as bigint}`) * 1000
|
200
|
+
const expires = new Date(time)
|
201
|
+
return this.proofService.isIntentExpirationWithinProofMinimumDate(intent.reward.prover, expires)
|
202
|
+
}
|
203
|
+
|
204
|
+
/**
|
205
|
+
* Checks that the intent destination is supported by the solver
|
206
|
+
* @param intent the source intent model
|
207
|
+
* @returns
|
208
|
+
*/
|
209
|
+
validDestination(intent: ValidationIntentInterface): boolean {
|
210
|
+
return this.ecoConfigService.getSupportedChains().includes(intent.route.destination)
|
211
|
+
}
|
212
|
+
|
213
|
+
/**
|
214
|
+
* Checks that the intent fulfillment is on a different chain than its source
|
215
|
+
* Needed since some proving methods(Hyperlane) cant prove same chain
|
216
|
+
* @param intent the source intent
|
217
|
+
* @param solver the solver used to fulfill
|
218
|
+
* @returns
|
219
|
+
*/
|
220
|
+
fulfillOnDifferentChain(intent: ValidationIntentInterface): boolean {
|
221
|
+
return intent.route.destination !== intent.route.source
|
222
|
+
}
|
223
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'
|
2
|
+
import { Observable } from 'rxjs'
|
3
|
+
import { map } from 'rxjs/operators'
|
4
|
+
|
5
|
+
@Injectable()
|
6
|
+
export class BigIntToStringInterceptor implements NestInterceptor {
|
7
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
8
|
+
return next.handle().pipe(map((data) => this.transformBigInt(data)))
|
9
|
+
}
|
10
|
+
|
11
|
+
private transformBigInt(data: any): any {
|
12
|
+
if (data === null || data === undefined) return data
|
13
|
+
|
14
|
+
if (typeof data === 'bigint') {
|
15
|
+
return data.toString()
|
16
|
+
}
|
17
|
+
|
18
|
+
if (Array.isArray(data)) {
|
19
|
+
return data.map((item) => this.transformBigInt(item))
|
20
|
+
}
|
21
|
+
|
22
|
+
if (typeof data === 'object') {
|
23
|
+
return Object.fromEntries(
|
24
|
+
Object.entries(data).map(([key, value]) => [key, this.transformBigInt(value)]),
|
25
|
+
)
|
26
|
+
}
|
27
|
+
|
28
|
+
return data
|
29
|
+
}
|
30
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { Module } from '@nestjs/common'
|
2
|
+
import { RetryInfeasableIntentsService } from '@/intervals/retry-infeasable-intents.service'
|
3
|
+
import { initBullMQ } from '@/bullmq/bullmq.helper'
|
4
|
+
import { QUEUES } from '@/common/redis/constants'
|
5
|
+
import { IntentModule } from '@/intent/intent.module'
|
6
|
+
import { ProverModule } from '@/prover/prover.module'
|
7
|
+
import { IntervalProcessor } from '@/bullmq/processors/interval.processor'
|
8
|
+
|
9
|
+
@Module({
|
10
|
+
imports: [
|
11
|
+
initBullMQ(QUEUES.INTERVAL),
|
12
|
+
initBullMQ(QUEUES.SOURCE_INTENT),
|
13
|
+
IntentModule,
|
14
|
+
ProverModule,
|
15
|
+
],
|
16
|
+
providers: [RetryInfeasableIntentsService, IntervalProcessor],
|
17
|
+
})
|
18
|
+
export class IntervalModule {}
|
@@ -0,0 +1,89 @@
|
|
1
|
+
import { EcoLogMessage } from '@/common/logging/eco-log-message'
|
2
|
+
import { QUEUES } from '@/common/redis/constants'
|
3
|
+
import { getIntentJobId } from '@/common/utils/strings'
|
4
|
+
import { Proofs } from '@/contracts'
|
5
|
+
import { EcoConfigService } from '@/eco-configs/eco-config.service'
|
6
|
+
import { IntentSourceModel } from '@/intent/schemas/intent-source.schema'
|
7
|
+
import { ProofService } from '@/prover/proof.service'
|
8
|
+
import { InjectQueue } from '@nestjs/bullmq'
|
9
|
+
import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common'
|
10
|
+
import { InjectModel } from '@nestjs/mongoose'
|
11
|
+
import { JobsOptions, Queue } from 'bullmq'
|
12
|
+
import { Model } from 'mongoose'
|
13
|
+
|
14
|
+
@Injectable()
|
15
|
+
export class RetryInfeasableIntentsService implements OnApplicationBootstrap {
|
16
|
+
private logger = new Logger(RetryInfeasableIntentsService.name)
|
17
|
+
private intentJobConfig: JobsOptions
|
18
|
+
|
19
|
+
constructor(
|
20
|
+
@InjectQueue(QUEUES.INTERVAL.queue) private readonly intervalQueue: Queue,
|
21
|
+
@InjectQueue(QUEUES.SOURCE_INTENT.queue) private readonly intentQueue: Queue,
|
22
|
+
@InjectModel(IntentSourceModel.name) private intentModel: Model<IntentSourceModel>,
|
23
|
+
private readonly proofService: ProofService,
|
24
|
+
private readonly ecoConfigService: EcoConfigService,
|
25
|
+
) {}
|
26
|
+
|
27
|
+
async onModuleInit() {
|
28
|
+
this.intentJobConfig = this.ecoConfigService.getIntervals().retryInfeasableIntents.jobTemplate
|
29
|
+
.opts as JobsOptions
|
30
|
+
}
|
31
|
+
|
32
|
+
async onApplicationBootstrap() {
|
33
|
+
const config = this.ecoConfigService.getIntervals().retryInfeasableIntents
|
34
|
+
config.repeatOpts = { ...config.repeatOpts, immediately: true }
|
35
|
+
config.jobTemplate = {
|
36
|
+
...config.jobTemplate,
|
37
|
+
name: QUEUES.INTERVAL.jobs.retry_infeasable_intents,
|
38
|
+
}
|
39
|
+
this.intervalQueue.upsertJobScheduler(
|
40
|
+
QUEUES.INTERVAL.jobs.RETRY_INFEASABLE_INTENTS,
|
41
|
+
config.repeatOpts,
|
42
|
+
config.jobTemplate,
|
43
|
+
)
|
44
|
+
}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Retries intents that are infeasable but still within the proof expiration window.
|
48
|
+
* Sends them on the {@link QUEUES.SOURCE_INTENT.jobs.retry_intent} queue to validate
|
49
|
+
*/
|
50
|
+
async retryInfeasableIntents() {
|
51
|
+
const models = await this.getInfeasableIntents()
|
52
|
+
this.logger.debug(
|
53
|
+
EcoLogMessage.fromDefault({
|
54
|
+
message: `retryInfeasableIntents`,
|
55
|
+
properties: {
|
56
|
+
models,
|
57
|
+
},
|
58
|
+
}),
|
59
|
+
)
|
60
|
+
|
61
|
+
const retryTasks = models.map(async (model) => {
|
62
|
+
const jobId = getIntentJobId('retry', model.intent.hash, model.intent.logIndex)
|
63
|
+
|
64
|
+
//add to processing queue
|
65
|
+
await this.intentQueue.add(QUEUES.SOURCE_INTENT.jobs.retry_intent, model.intent.hash, {
|
66
|
+
jobId,
|
67
|
+
...this.intentJobConfig,
|
68
|
+
})
|
69
|
+
})
|
70
|
+
|
71
|
+
await Promise.all(retryTasks)
|
72
|
+
}
|
73
|
+
|
74
|
+
private async getInfeasableIntents() {
|
75
|
+
return await this.intentModel.find({
|
76
|
+
status: 'INFEASABLE',
|
77
|
+
$or: [
|
78
|
+
{
|
79
|
+
'intent.expiration': { $gt: this.proofService.getProofMinimumDate(Proofs.Hyperlane) },
|
80
|
+
'intent.prover': { $in: this.proofService.getProvers(Proofs.Hyperlane) },
|
81
|
+
},
|
82
|
+
{
|
83
|
+
'intent.expiration': { $gt: this.proofService.getProofMinimumDate(Proofs.Storage) },
|
84
|
+
'intent.prover': { $in: this.proofService.getProvers(Proofs.Storage) },
|
85
|
+
},
|
86
|
+
],
|
87
|
+
})
|
88
|
+
}
|
89
|
+
}
|