eco-solver 0.0.1-security → 1.5.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.

Potentially problematic release.


This version of eco-solver might be problematic. Click here for more details.

Files changed (244) hide show
  1. package/.eslintignore +8 -0
  2. package/.eslintrc.js +24 -0
  3. package/.github/workflows/ci.yaml +38 -0
  4. package/.nvmrc +1 -0
  5. package/.prettierignore +3 -0
  6. package/.prettierrc +8 -0
  7. package/Dockerfile +11 -0
  8. package/LICENSE +21 -0
  9. package/README.md +29 -5
  10. package/config/default.ts +135 -0
  11. package/config/development.ts +95 -0
  12. package/config/preproduction.ts +17 -0
  13. package/config/production.ts +17 -0
  14. package/config/staging.ts +17 -0
  15. package/config/test.ts +7 -0
  16. package/index.js +66 -0
  17. package/jest.config.ts +14 -0
  18. package/nest-cli.json +8 -0
  19. package/package.json +115 -6
  20. package/src/api/api.module.ts +27 -0
  21. package/src/api/balance.controller.ts +41 -0
  22. package/src/api/quote.controller.ts +54 -0
  23. package/src/api/tests/balance.controller.spec.ts +113 -0
  24. package/src/api/tests/quote.controller.spec.ts +83 -0
  25. package/src/app.module.ts +74 -0
  26. package/src/balance/balance.module.ts +14 -0
  27. package/src/balance/balance.service.ts +230 -0
  28. package/src/balance/balance.ws.service.ts +104 -0
  29. package/src/balance/types.ts +16 -0
  30. package/src/bullmq/bullmq.helper.ts +41 -0
  31. package/src/bullmq/processors/eth-ws.processor.ts +47 -0
  32. package/src/bullmq/processors/inbox.processor.ts +55 -0
  33. package/src/bullmq/processors/interval.processor.ts +54 -0
  34. package/src/bullmq/processors/processor.module.ts +14 -0
  35. package/src/bullmq/processors/signer.processor.ts +41 -0
  36. package/src/bullmq/processors/solve-intent.processor.ts +73 -0
  37. package/src/bullmq/processors/tests/solve-intent.processor.spec.ts +3 -0
  38. package/src/bullmq/utils/queue.ts +22 -0
  39. package/src/chain-monitor/chain-monitor.module.ts +12 -0
  40. package/src/chain-monitor/chain-sync.service.ts +134 -0
  41. package/src/chain-monitor/tests/chain-sync.service.spec.ts +190 -0
  42. package/src/commander/.eslintrc.js +6 -0
  43. package/src/commander/balance/balance-command.module.ts +12 -0
  44. package/src/commander/balance/balance.command.ts +73 -0
  45. package/src/commander/command-main.ts +15 -0
  46. package/src/commander/commander-app.module.ts +31 -0
  47. package/src/commander/eco-config.command.ts +20 -0
  48. package/src/commander/safe/safe-command.module.ts +11 -0
  49. package/src/commander/safe/safe.command.ts +70 -0
  50. package/src/commander/transfer/client.command.ts +24 -0
  51. package/src/commander/transfer/transfer-command.module.ts +26 -0
  52. package/src/commander/transfer/transfer.command.ts +138 -0
  53. package/src/commander/utils.ts +8 -0
  54. package/src/common/chains/definitions/arbitrum.ts +12 -0
  55. package/src/common/chains/definitions/base.ts +21 -0
  56. package/src/common/chains/definitions/eco.ts +54 -0
  57. package/src/common/chains/definitions/ethereum.ts +22 -0
  58. package/src/common/chains/definitions/helix.ts +53 -0
  59. package/src/common/chains/definitions/mantle.ts +12 -0
  60. package/src/common/chains/definitions/optimism.ts +22 -0
  61. package/src/common/chains/definitions/polygon.ts +12 -0
  62. package/src/common/chains/supported.ts +26 -0
  63. package/src/common/chains/transport.ts +19 -0
  64. package/src/common/errors/eco-error.ts +155 -0
  65. package/src/common/events/constants.ts +3 -0
  66. package/src/common/events/viem.ts +22 -0
  67. package/src/common/logging/eco-log-message.ts +74 -0
  68. package/src/common/redis/constants.ts +55 -0
  69. package/src/common/redis/redis-connection-utils.ts +106 -0
  70. package/src/common/routes/constants.ts +3 -0
  71. package/src/common/utils/objects.ts +34 -0
  72. package/src/common/utils/strings.ts +49 -0
  73. package/src/common/utils/tests/objects.spec.ts +23 -0
  74. package/src/common/utils/tests/strings.spec.ts +22 -0
  75. package/src/common/viem/contracts.ts +25 -0
  76. package/src/common/viem/tests/utils.spec.ts +115 -0
  77. package/src/common/viem/utils.ts +78 -0
  78. package/src/contracts/ERC20.contract.ts +389 -0
  79. package/src/contracts/EntryPoint.V6.contract.ts +1309 -0
  80. package/src/contracts/KernelAccount.abi.ts +87 -0
  81. package/src/contracts/OwnableExecutor.abi.ts +128 -0
  82. package/src/contracts/SimpleAccount.contract.ts +524 -0
  83. package/src/contracts/inbox.ts +8 -0
  84. package/src/contracts/index.ts +9 -0
  85. package/src/contracts/intent-source.ts +55 -0
  86. package/src/contracts/interfaces/index.ts +1 -0
  87. package/src/contracts/interfaces/prover.interface.ts +22 -0
  88. package/src/contracts/prover.ts +9 -0
  89. package/src/contracts/tests/erc20.contract.spec.ts +59 -0
  90. package/src/contracts/utils.ts +31 -0
  91. package/src/decoder/decoder.interface.ts +3 -0
  92. package/src/decoder/tests/utils.spec.ts +36 -0
  93. package/src/decoder/utils.ts +24 -0
  94. package/src/decorators/cacheable.decorator.ts +48 -0
  95. package/src/eco-configs/aws-config.service.ts +75 -0
  96. package/src/eco-configs/eco-config.module.ts +44 -0
  97. package/src/eco-configs/eco-config.service.ts +220 -0
  98. package/src/eco-configs/eco-config.types.ts +278 -0
  99. package/src/eco-configs/interfaces/config-source.interface.ts +3 -0
  100. package/src/eco-configs/tests/aws-config.service.spec.ts +52 -0
  101. package/src/eco-configs/tests/eco-config.service.spec.ts +137 -0
  102. package/src/eco-configs/tests/utils.spec.ts +84 -0
  103. package/src/eco-configs/utils.ts +49 -0
  104. package/src/fee/fee.module.ts +10 -0
  105. package/src/fee/fee.service.ts +467 -0
  106. package/src/fee/tests/fee.service.spec.ts +909 -0
  107. package/src/fee/tests/utils.spec.ts +49 -0
  108. package/src/fee/types.ts +44 -0
  109. package/src/fee/utils.ts +23 -0
  110. package/src/flags/flags.module.ts +10 -0
  111. package/src/flags/flags.service.ts +112 -0
  112. package/src/flags/tests/flags.service.spec.ts +68 -0
  113. package/src/flags/utils.ts +22 -0
  114. package/src/health/constants.ts +1 -0
  115. package/src/health/health.controller.ts +23 -0
  116. package/src/health/health.module.ts +25 -0
  117. package/src/health/health.service.ts +40 -0
  118. package/src/health/indicators/balance.indicator.ts +196 -0
  119. package/src/health/indicators/eco-redis.indicator.ts +23 -0
  120. package/src/health/indicators/git-commit.indicator.ts +67 -0
  121. package/src/health/indicators/mongodb.indicator.ts +11 -0
  122. package/src/health/indicators/permission.indicator.ts +64 -0
  123. package/src/intent/create-intent.service.ts +129 -0
  124. package/src/intent/feasable-intent.service.ts +80 -0
  125. package/src/intent/fulfill-intent.service.ts +318 -0
  126. package/src/intent/intent.controller.ts +199 -0
  127. package/src/intent/intent.module.ts +49 -0
  128. package/src/intent/schemas/intent-call-data.schema.ts +16 -0
  129. package/src/intent/schemas/intent-data.schema.ts +114 -0
  130. package/src/intent/schemas/intent-source.schema.ts +33 -0
  131. package/src/intent/schemas/intent-token-amount.schema.ts +14 -0
  132. package/src/intent/schemas/reward-data.schema.ts +48 -0
  133. package/src/intent/schemas/route-data.schema.ts +52 -0
  134. package/src/intent/schemas/watch-event.schema.ts +32 -0
  135. package/src/intent/tests/create-intent.service.spec.ts +215 -0
  136. package/src/intent/tests/feasable-intent.service.spec.ts +155 -0
  137. package/src/intent/tests/fulfill-intent.service.spec.ts +564 -0
  138. package/src/intent/tests/utils-intent.service.spec.ts +308 -0
  139. package/src/intent/tests/utils.spec.ts +62 -0
  140. package/src/intent/tests/validate-intent.service.spec.ts +297 -0
  141. package/src/intent/tests/validation.service.spec.ts +337 -0
  142. package/src/intent/utils-intent.service.ts +168 -0
  143. package/src/intent/utils.ts +37 -0
  144. package/src/intent/validate-intent.service.ts +176 -0
  145. package/src/intent/validation.sevice.ts +223 -0
  146. package/src/interceptors/big-int.interceptor.ts +30 -0
  147. package/src/intervals/interval.module.ts +18 -0
  148. package/src/intervals/retry-infeasable-intents.service.ts +89 -0
  149. package/src/intervals/tests/retry-infeasable-intents.service.spec.ts +167 -0
  150. package/src/kms/errors.ts +0 -0
  151. package/src/kms/kms.module.ts +12 -0
  152. package/src/kms/kms.service.ts +65 -0
  153. package/src/kms/tests/kms.service.spec.ts +60 -0
  154. package/src/liquidity-manager/jobs/check-balances-cron.job.ts +229 -0
  155. package/src/liquidity-manager/jobs/liquidity-manager.job.ts +52 -0
  156. package/src/liquidity-manager/jobs/rebalance.job.ts +61 -0
  157. package/src/liquidity-manager/liquidity-manager.module.ts +29 -0
  158. package/src/liquidity-manager/processors/base.processor.ts +117 -0
  159. package/src/liquidity-manager/processors/eco-protocol-intents.processor.ts +34 -0
  160. package/src/liquidity-manager/processors/grouped-jobs.processor.ts +103 -0
  161. package/src/liquidity-manager/queues/liquidity-manager.queue.ts +48 -0
  162. package/src/liquidity-manager/schemas/rebalance-token.schema.ts +32 -0
  163. package/src/liquidity-manager/schemas/rebalance.schema.ts +32 -0
  164. package/src/liquidity-manager/services/liquidity-manager.service.ts +188 -0
  165. package/src/liquidity-manager/services/liquidity-provider.service.ts +25 -0
  166. package/src/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service.spec.ts +125 -0
  167. package/src/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service.ts +117 -0
  168. package/src/liquidity-manager/services/liquidity-providers/LiFi/utils/get-transaction-hashes.ts +16 -0
  169. package/src/liquidity-manager/tests/liquidity-manager.service.spec.ts +142 -0
  170. package/src/liquidity-manager/types/token-state.enum.ts +5 -0
  171. package/src/liquidity-manager/types/types.d.ts +52 -0
  172. package/src/liquidity-manager/utils/address.ts +5 -0
  173. package/src/liquidity-manager/utils/math.ts +9 -0
  174. package/src/liquidity-manager/utils/serialize.spec.ts +24 -0
  175. package/src/liquidity-manager/utils/serialize.ts +47 -0
  176. package/src/liquidity-manager/utils/token.ts +91 -0
  177. package/src/main.ts +63 -0
  178. package/src/nest-redlock/nest-redlock.config.ts +14 -0
  179. package/src/nest-redlock/nest-redlock.interface.ts +5 -0
  180. package/src/nest-redlock/nest-redlock.module.ts +64 -0
  181. package/src/nest-redlock/nest-redlock.service.ts +59 -0
  182. package/src/prover/proof.service.ts +184 -0
  183. package/src/prover/prover.module.ts +10 -0
  184. package/src/prover/tests/proof.service.spec.ts +154 -0
  185. package/src/quote/dto/quote.intent.data.dto.ts +35 -0
  186. package/src/quote/dto/quote.reward.data.dto.ts +67 -0
  187. package/src/quote/dto/quote.route.data.dto.ts +71 -0
  188. package/src/quote/dto/types.ts +18 -0
  189. package/src/quote/errors.ts +215 -0
  190. package/src/quote/quote.module.ts +17 -0
  191. package/src/quote/quote.service.ts +299 -0
  192. package/src/quote/schemas/quote-call.schema.ts +16 -0
  193. package/src/quote/schemas/quote-intent.schema.ts +27 -0
  194. package/src/quote/schemas/quote-reward.schema.ts +24 -0
  195. package/src/quote/schemas/quote-route.schema.ts +30 -0
  196. package/src/quote/schemas/quote-token.schema.ts +14 -0
  197. package/src/quote/tests/quote.service.spec.ts +444 -0
  198. package/src/sign/atomic-signer.service.ts +24 -0
  199. package/src/sign/atomic.nonce.service.ts +114 -0
  200. package/src/sign/kms-account/kmsToAccount.ts +73 -0
  201. package/src/sign/kms-account/signKms.ts +30 -0
  202. package/src/sign/kms-account/signKmsTransaction.ts +37 -0
  203. package/src/sign/kms-account/signKmsTypedData.ts +21 -0
  204. package/src/sign/nonce.service.ts +89 -0
  205. package/src/sign/schemas/nonce.schema.ts +36 -0
  206. package/src/sign/sign.controller.ts +52 -0
  207. package/src/sign/sign.helper.ts +23 -0
  208. package/src/sign/sign.module.ts +27 -0
  209. package/src/sign/signer-kms.service.ts +27 -0
  210. package/src/sign/signer.service.ts +26 -0
  211. package/src/solver/filters/tests/valid-smart-wallet.service.spec.ts +87 -0
  212. package/src/solver/filters/valid-smart-wallet.service.ts +58 -0
  213. package/src/solver/solver.module.ts +10 -0
  214. package/src/transaction/multichain-public-client.service.ts +15 -0
  215. package/src/transaction/smart-wallets/kernel/actions/encodeData.kernel.ts +57 -0
  216. package/src/transaction/smart-wallets/kernel/create-kernel-client-v2.account.ts +183 -0
  217. package/src/transaction/smart-wallets/kernel/create.kernel.account.ts +270 -0
  218. package/src/transaction/smart-wallets/kernel/index.ts +2 -0
  219. package/src/transaction/smart-wallets/kernel/kernel-account-client-v2.service.ts +90 -0
  220. package/src/transaction/smart-wallets/kernel/kernel-account-client.service.ts +107 -0
  221. package/src/transaction/smart-wallets/kernel/kernel-account.client.ts +105 -0
  222. package/src/transaction/smart-wallets/kernel/kernel-account.config.ts +34 -0
  223. package/src/transaction/smart-wallets/simple-account/create.simple.account.ts +19 -0
  224. package/src/transaction/smart-wallets/simple-account/index.ts +2 -0
  225. package/src/transaction/smart-wallets/simple-account/simple-account-client.service.ts +42 -0
  226. package/src/transaction/smart-wallets/simple-account/simple-account.client.ts +83 -0
  227. package/src/transaction/smart-wallets/simple-account/simple-account.config.ts +5 -0
  228. package/src/transaction/smart-wallets/smart-wallet.types.ts +38 -0
  229. package/src/transaction/smart-wallets/utils.ts +14 -0
  230. package/src/transaction/transaction.module.ts +25 -0
  231. package/src/transaction/viem_multichain_client.service.ts +100 -0
  232. package/src/transforms/viem-address.decorator.ts +14 -0
  233. package/src/utils/bigint.ts +44 -0
  234. package/src/utils/types.ts +18 -0
  235. package/src/watch/intent/tests/watch-create-intent.service.spec.ts +257 -0
  236. package/src/watch/intent/tests/watch-fulfillment.service.spec.ts +141 -0
  237. package/src/watch/intent/watch-create-intent.service.ts +106 -0
  238. package/src/watch/intent/watch-event.service.ts +133 -0
  239. package/src/watch/intent/watch-fulfillment.service.ts +115 -0
  240. package/src/watch/watch.module.ts +13 -0
  241. package/test/app.e2e-spec.ts +21 -0
  242. package/test/jest-e2e.json +9 -0
  243. package/tsconfig.build.json +4 -0
  244. package/tsconfig.json +29 -0
@@ -0,0 +1,104 @@
1
+ import { Injectable, Logger, OnApplicationBootstrap, OnModuleDestroy } from '@nestjs/common'
2
+ import { EcoConfigService } from '../eco-configs/eco-config.service'
3
+ import { Network } from 'alchemy-sdk'
4
+ import { JobsOptions, Queue } from 'bullmq'
5
+ import { QUEUES } from '../common/redis/constants'
6
+ import { InjectQueue } from '@nestjs/bullmq'
7
+ import { ViemEventLog } from '../common/events/viem'
8
+ import { erc20Abi, Hex, WatchContractEventReturnType, zeroHash } from 'viem'
9
+ import { convertBigIntsToStrings } from '../common/viem/utils'
10
+ import { EcoLogMessage } from '../common/logging/eco-log-message'
11
+ import { getIntentJobId } from '../common/utils/strings'
12
+ import { KernelAccountClientService } from '../transaction/smart-wallets/kernel/kernel-account-client.service'
13
+ import { EcoError } from '@/common/errors/eco-error'
14
+
15
+ @Injectable()
16
+ export class BalanceWebsocketService implements OnApplicationBootstrap, OnModuleDestroy {
17
+ private logger = new Logger(BalanceWebsocketService.name)
18
+ private intentJobConfig: JobsOptions
19
+ private unwatch: Record<string, WatchContractEventReturnType> = {}
20
+
21
+ constructor(
22
+ @InjectQueue(QUEUES.ETH_SOCKET.queue) private readonly ethQueue: Queue,
23
+ private readonly kernelAccountClientService: KernelAccountClientService,
24
+ private readonly ecoConfigService: EcoConfigService,
25
+ ) {}
26
+
27
+ async onApplicationBootstrap() {
28
+ await this.subscribeWS()
29
+ }
30
+
31
+ async onModuleDestroy() {
32
+ // close all websockets
33
+ try {
34
+ Object.values(this.unwatch).forEach((unwatch) => unwatch())
35
+ } catch (e) {
36
+ this.logger.error(
37
+ EcoLogMessage.withError({
38
+ message: `watch-event: unsubscribe`,
39
+ error: EcoError.WatchEventUnsubscribeError,
40
+ properties: {
41
+ errorPassed: e,
42
+ },
43
+ }),
44
+ )
45
+ }
46
+ }
47
+
48
+ async subscribeWS() {
49
+ this.intentJobConfig = this.ecoConfigService.getRedis().jobs.intentJobConfig
50
+
51
+ const websocketTasks = Object.entries(this.ecoConfigService.getSolvers()).map(
52
+ async ([, solver]) => {
53
+ const client = await this.kernelAccountClientService.getClient(solver.chainID)
54
+ // const instanceAddress = this.alchemyService.getWallet(solver.network).address
55
+
56
+ Object.entries(solver.targets).forEach(([address, source]) => {
57
+ // const [address, source] = targetEntity
58
+ if (source.contractType === 'erc20') {
59
+ this.unwatch[`${solver.chainID}-${address}`] = client.watchContractEvent({
60
+ address: address as Hex,
61
+ abi: erc20Abi,
62
+ eventName: 'Transfer',
63
+ // restrict transfers from anyone to the simple account address
64
+ args: { to: client.kernelAccount.address },
65
+ onLogs: this.addJob(solver.network, solver.chainID) as any,
66
+ })
67
+ }
68
+ })
69
+ },
70
+ )
71
+ await Promise.all(websocketTasks)
72
+ }
73
+
74
+ addJob(network: Network, chainID: number) {
75
+ return async (logs: ViemEventLog[]) => {
76
+ const logTasks = logs.map((transferEvent) => {
77
+ transferEvent.sourceChainID = BigInt(chainID)
78
+ //add network to the event
79
+ transferEvent.sourceNetwork = network
80
+
81
+ //bigint as it cant serialize to json
82
+ transferEvent = convertBigIntsToStrings(transferEvent)
83
+ this.logger.debug(
84
+ EcoLogMessage.fromDefault({
85
+ message: `ws: balance transfer`,
86
+ properties: {
87
+ transferEvent: transferEvent,
88
+ },
89
+ }),
90
+ )
91
+ //add to processing queue
92
+ return this.ethQueue.add(QUEUES.ETH_SOCKET.jobs.erc20_balance_socket, transferEvent, {
93
+ jobId: getIntentJobId(
94
+ 'websocket',
95
+ transferEvent.transactionHash ?? zeroHash,
96
+ transferEvent.logIndex ?? 0,
97
+ ),
98
+ ...this.intentJobConfig,
99
+ })
100
+ })
101
+ await Promise.all(logTasks)
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,16 @@
1
+ import { TargetContractType } from '@/eco-configs/eco-config.types'
2
+ import { Hex } from 'viem'
3
+
4
+ export type TokenConfig = {
5
+ address: Hex
6
+ chainId: number
7
+ minBalance: number
8
+ targetBalance: number
9
+ type: TargetContractType
10
+ }
11
+
12
+ export type TokenBalance = {
13
+ address: Hex
14
+ decimals: number
15
+ balance: bigint
16
+ }
@@ -0,0 +1,41 @@
1
+ import { BullModule, RegisterQueueOptions } from '@nestjs/bullmq'
2
+ import { DynamicModule } from '@nestjs/common'
3
+ import { EcoConfigService } from '@/eco-configs/eco-config.service'
4
+ import { RedisConnectionUtils } from '@/common/redis/redis-connection-utils'
5
+ import { QueueMetadata } from '@/common/redis/constants'
6
+
7
+ /**
8
+ * Initialize the BullMQ queue with the given token and eco configs
9
+ * @param {QueueMetadata} queueInterface queue interface
10
+ * @param {Partial<RegisterQueueOptions>} opts queue options
11
+ * @returns
12
+ */
13
+ export function initBullMQ(
14
+ queueInterface: QueueMetadata,
15
+ opts?: Partial<RegisterQueueOptions>,
16
+ ): DynamicModule {
17
+ return BullModule.registerQueueAsync({
18
+ name: queueInterface.queue,
19
+ useFactory: (configService: EcoConfigService) => {
20
+ return {
21
+ ...RedisConnectionUtils.getQueueOptions(queueInterface, configService.getRedis()),
22
+ ...opts,
23
+ }
24
+ },
25
+ inject: [EcoConfigService],
26
+ })
27
+ }
28
+
29
+ /**
30
+ * Initialize the BullMQ flow with the given name and eco configs
31
+ * @param {QueueMetadata} queueInterface queue interface
32
+ * @returns
33
+ */
34
+ export function initFlowBullMQ(queueInterface: QueueMetadata): DynamicModule {
35
+ return BullModule.registerFlowProducerAsync({
36
+ name: queueInterface.queue,
37
+ useFactory: (configService: EcoConfigService) =>
38
+ RedisConnectionUtils.getQueueOptions(queueInterface, configService.getRedis()),
39
+ inject: [EcoConfigService],
40
+ })
41
+ }
@@ -0,0 +1,47 @@
1
+ import { Processor, WorkerHost } from '@nestjs/bullmq'
2
+ import { QUEUES } from '../../common/redis/constants'
3
+ import { Injectable, Logger } from '@nestjs/common'
4
+ import { Job } from 'bullmq'
5
+ import { EcoLogMessage } from '../../common/logging/eco-log-message'
6
+ import { BalanceService } from '../../balance/balance.service'
7
+ import { ViemEventLog } from '../../common/events/viem'
8
+
9
+ @Injectable()
10
+ @Processor(QUEUES.ETH_SOCKET.queue)
11
+ export class EthWebsocketProcessor extends WorkerHost {
12
+ private logger = new Logger(EthWebsocketProcessor.name)
13
+ constructor(private readonly balanceService: BalanceService) {
14
+ super()
15
+ }
16
+
17
+ async process(
18
+ job: Job<any, any, string>,
19
+ processToken?: string | undefined, // eslint-disable-line @typescript-eslint/no-unused-vars
20
+ ): Promise<any> {
21
+ this.logger.debug(
22
+ EcoLogMessage.fromDefault({
23
+ message: `EthWebsocketProcessor: process`,
24
+ }),
25
+ )
26
+
27
+ switch (job.name) {
28
+ case QUEUES.ETH_SOCKET.jobs.erc20_balance_socket:
29
+ this.logger.debug(
30
+ EcoLogMessage.fromDefault({
31
+ message: `EthWebsocketProcessor: ws event`,
32
+ properties: {
33
+ event: job.data,
34
+ },
35
+ }),
36
+ )
37
+ return this.balanceService.updateBalance(job.data as ViemEventLog)
38
+ default:
39
+ this.logger.error(
40
+ EcoLogMessage.fromDefault({
41
+ message: `EthWebsocketProcessor: Invalid job type ${job.name}`,
42
+ }),
43
+ )
44
+ return Promise.reject('Invalid job type')
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,55 @@
1
+ import { OnWorkerEvent, Processor, WorkerHost } from '@nestjs/bullmq'
2
+ import { QUEUES } from '@/common/redis/constants'
3
+ import { Injectable, Logger } from '@nestjs/common'
4
+ import { Job } from 'bullmq'
5
+ import { EcoLogMessage } from '@/common/logging/eco-log-message'
6
+ import { UtilsIntentService } from '@/intent/utils-intent.service'
7
+ import { FulfillmentLog } from '@/contracts/inbox'
8
+
9
+ @Injectable()
10
+ @Processor(QUEUES.INBOX.queue)
11
+ export class InboxProcessor extends WorkerHost {
12
+ private logger = new Logger(InboxProcessor.name)
13
+ constructor(private readonly utilsIntentService: UtilsIntentService) {
14
+ super()
15
+ }
16
+
17
+ async process(
18
+ job: Job<any, any, string>,
19
+ processToken?: string | undefined, // eslint-disable-line @typescript-eslint/no-unused-vars
20
+ ): Promise<any> {
21
+ this.logger.debug(
22
+ EcoLogMessage.fromDefault({
23
+ message: `InboxProcessor: process`,
24
+ properties: {
25
+ job: job.name,
26
+ },
27
+ }),
28
+ )
29
+
30
+ switch (job.name) {
31
+ case QUEUES.INBOX.jobs.fulfillment:
32
+ return await this.utilsIntentService.updateOnFulfillment(job.data as FulfillmentLog)
33
+ default:
34
+ this.logger.error(
35
+ EcoLogMessage.fromDefault({
36
+ message: `InboxProcessor: Invalid job type ${job.name}`,
37
+ }),
38
+ )
39
+ return Promise.reject('Invalid job type')
40
+ }
41
+ }
42
+
43
+ @OnWorkerEvent('failed')
44
+ onJobFailed(job: Job<any, any, string>, error: Error) {
45
+ this.logger.error(
46
+ EcoLogMessage.fromDefault({
47
+ message: `InboxProcessor: Error processing job`,
48
+ properties: {
49
+ job,
50
+ error,
51
+ },
52
+ }),
53
+ )
54
+ }
55
+ }
@@ -0,0 +1,54 @@
1
+ import { OnWorkerEvent, Processor, WorkerHost } from '@nestjs/bullmq'
2
+ import { QUEUES } from '@/common/redis/constants'
3
+ import { Injectable, Logger } from '@nestjs/common'
4
+ import { Job } from 'bullmq'
5
+ import { EcoLogMessage } from '@/common/logging/eco-log-message'
6
+ import { RetryInfeasableIntentsService } from '@/intervals/retry-infeasable-intents.service'
7
+
8
+ @Injectable()
9
+ @Processor(QUEUES.INTERVAL.queue)
10
+ export class IntervalProcessor extends WorkerHost {
11
+ private logger = new Logger(IntervalProcessor.name)
12
+ constructor(private readonly retryInfeasableIntentsService: RetryInfeasableIntentsService) {
13
+ super()
14
+ }
15
+
16
+ async process(
17
+ job: Job<any, any, string>,
18
+ processToken?: string | undefined, // eslint-disable-line @typescript-eslint/no-unused-vars
19
+ ): Promise<any> {
20
+ this.logger.debug(
21
+ EcoLogMessage.fromDefault({
22
+ message: `IntervalProcessor: process`,
23
+ properties: {
24
+ job: job.name,
25
+ },
26
+ }),
27
+ )
28
+
29
+ switch (job.name) {
30
+ case QUEUES.INTERVAL.jobs.retry_infeasable_intents:
31
+ return await this.retryInfeasableIntentsService.retryInfeasableIntents()
32
+ default:
33
+ this.logger.error(
34
+ EcoLogMessage.fromDefault({
35
+ message: `IntervalProcessor: Invalid job type ${job.name}`,
36
+ }),
37
+ )
38
+ return Promise.reject('Invalid job type')
39
+ }
40
+ }
41
+
42
+ @OnWorkerEvent('failed')
43
+ onJobFailed(job: Job<any, any, string>, error: Error) {
44
+ this.logger.error(
45
+ EcoLogMessage.fromDefault({
46
+ message: `IntervalProcessor: Error processing job`,
47
+ properties: {
48
+ job,
49
+ error,
50
+ },
51
+ }),
52
+ )
53
+ }
54
+ }
@@ -0,0 +1,14 @@
1
+ import { Module } from '@nestjs/common'
2
+ import { EthWebsocketProcessor } from './eth-ws.processor'
3
+ import { SignerProcessor } from './signer.processor'
4
+ import { SolveIntentProcessor } from './solve-intent.processor'
5
+ import { BalanceModule } from '../../balance/balance.module'
6
+ import { IntentModule } from '../../intent/intent.module'
7
+ import { SignModule } from '../../sign/sign.module'
8
+ import { InboxProcessor } from '@/bullmq/processors/inbox.processor'
9
+
10
+ @Module({
11
+ imports: [BalanceModule, IntentModule, SignModule],
12
+ providers: [EthWebsocketProcessor, SignerProcessor, SolveIntentProcessor, InboxProcessor],
13
+ })
14
+ export class ProcessorModule {}
@@ -0,0 +1,41 @@
1
+ import { Processor, WorkerHost } from '@nestjs/bullmq'
2
+ import { QUEUES } from '../../common/redis/constants'
3
+ import { Injectable, Logger } from '@nestjs/common'
4
+ import { Job } from 'bullmq'
5
+ import { EcoLogMessage } from '../../common/logging/eco-log-message'
6
+ import { NonceService } from '../../sign/nonce.service'
7
+
8
+ @Injectable()
9
+ @Processor(QUEUES.SIGNER.queue)
10
+ export class SignerProcessor extends WorkerHost {
11
+ private logger = new Logger(SignerProcessor.name)
12
+ constructor(private readonly nonceService: NonceService) {
13
+ super()
14
+ }
15
+
16
+ async process(
17
+ job: Job<any, any, string>,
18
+ processToken?: string | undefined, // eslint-disable-line @typescript-eslint/no-unused-vars
19
+ ): Promise<any> {
20
+ this.logger.debug(
21
+ EcoLogMessage.fromDefault({
22
+ message: `SignerProcessor: process`,
23
+ properties: {
24
+ job: job.name,
25
+ },
26
+ }),
27
+ )
28
+
29
+ switch (job.name) {
30
+ case QUEUES.SIGNER.jobs.nonce_sync:
31
+ return this.nonceService.syncNonces()
32
+ default:
33
+ this.logger.error(
34
+ EcoLogMessage.fromDefault({
35
+ message: `SignerProcessor: Invalid job type ${job.name}`,
36
+ }),
37
+ )
38
+ return Promise.reject('Invalid job type')
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,73 @@
1
+ import { OnWorkerEvent, Processor, WorkerHost } from '@nestjs/bullmq'
2
+ import { QUEUES } from '@/common/redis/constants'
3
+ import { Injectable, Logger } from '@nestjs/common'
4
+ import { Job } from 'bullmq'
5
+ import { EcoLogMessage } from '@/common/logging/eco-log-message'
6
+ import { FeasableIntentService } from '@/intent/feasable-intent.service'
7
+ import { ValidateIntentService } from '@/intent/validate-intent.service'
8
+ import { CreateIntentService } from '@/intent/create-intent.service'
9
+ import { FulfillIntentService } from '@/intent/fulfill-intent.service'
10
+ import { Hex } from 'viem'
11
+ import { IntentCreatedLog } from '@/contracts'
12
+ import { Serialize } from '@/liquidity-manager/utils/serialize'
13
+
14
+ @Injectable()
15
+ @Processor(QUEUES.SOURCE_INTENT.queue)
16
+ export class SolveIntentProcessor extends WorkerHost {
17
+ private logger = new Logger(SolveIntentProcessor.name)
18
+
19
+ constructor(
20
+ private readonly createIntentService: CreateIntentService,
21
+ private readonly validateIntentService: ValidateIntentService,
22
+ private readonly feasableIntentService: FeasableIntentService,
23
+ private readonly fulfillIntentService: FulfillIntentService,
24
+ ) {
25
+ super()
26
+ }
27
+
28
+ async process(
29
+ job: Job<any, any, string>,
30
+ processToken?: string | undefined, // eslint-disable-line @typescript-eslint/no-unused-vars
31
+ ): Promise<any> {
32
+ this.logger.debug(
33
+ EcoLogMessage.fromDefault({
34
+ message: `SolveIntentProcessor: process`,
35
+ properties: {
36
+ job: job.name,
37
+ },
38
+ }),
39
+ )
40
+
41
+ switch (job.name) {
42
+ case QUEUES.SOURCE_INTENT.jobs.create_intent:
43
+ return await this.createIntentService.createIntent(job.data as Serialize<IntentCreatedLog>)
44
+ case QUEUES.SOURCE_INTENT.jobs.validate_intent:
45
+ case QUEUES.SOURCE_INTENT.jobs.retry_intent:
46
+ return await this.validateIntentService.validateIntent(job.data as Hex)
47
+ case QUEUES.SOURCE_INTENT.jobs.feasable_intent:
48
+ return await this.feasableIntentService.feasableIntent(job.data as Hex)
49
+ case QUEUES.SOURCE_INTENT.jobs.fulfill_intent:
50
+ return await this.fulfillIntentService.executeFulfillIntent(job.data as Hex)
51
+ default:
52
+ this.logger.error(
53
+ EcoLogMessage.fromDefault({
54
+ message: `SolveIntentProcessor: Invalid job type ${job.name}`,
55
+ }),
56
+ )
57
+ return Promise.reject('Invalid job type')
58
+ }
59
+ }
60
+
61
+ @OnWorkerEvent('failed')
62
+ onJobFailed(job: Job<any, any, string>, error: Error) {
63
+ this.logger.error(
64
+ EcoLogMessage.fromDefault({
65
+ message: `SolveIntentProcessor: Error processing job`,
66
+ properties: {
67
+ job,
68
+ error,
69
+ },
70
+ }),
71
+ )
72
+ }
73
+ }
@@ -0,0 +1,3 @@
1
+ describe('Solve Intent Processor tests', () => {
2
+ it('should ', async () => {})
3
+ })
@@ -0,0 +1,22 @@
1
+ import { Queue } from 'bullmq'
2
+
3
+ export async function removeJobSchedulers(queue: Queue, jobName: string) {
4
+ const repeatableJobs = await queue.getJobSchedulers()
5
+
6
+ for (const job of repeatableJobs) {
7
+ if (job.name === jobName) {
8
+ await queue.removeJobScheduler(job.key)
9
+ }
10
+ }
11
+ }
12
+
13
+ /**
14
+ * Checks to see if there is a scheduled job of a given name in the queue.
15
+ * @param queue the queue to check
16
+ * @param jobName the name of the job to check
17
+ * @returns
18
+ */
19
+ export async function isJobScheduled(queue: Queue, jobName: string): Promise<boolean> {
20
+ const repeatableJobs = await queue.getJobSchedulers()
21
+ return !!repeatableJobs.find((job) => job.name === jobName)
22
+ }
@@ -0,0 +1,12 @@
1
+ import { Module } from '@nestjs/common'
2
+ import { IntentModule } from '../intent/intent.module'
3
+ import { ChainSyncService } from './chain-sync.service'
4
+ import { TransactionModule } from '../transaction/transaction.module'
5
+ import { WatchModule } from '@/watch/watch.module'
6
+
7
+ @Module({
8
+ imports: [IntentModule, TransactionModule, WatchModule],
9
+ providers: [ChainSyncService],
10
+ exports: [ChainSyncService],
11
+ })
12
+ export class ChainMonitorModule {}
@@ -0,0 +1,134 @@
1
+ import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common'
2
+ import { InjectModel } from '@nestjs/mongoose'
3
+ import { Model } from 'mongoose'
4
+ import { IntentSourceModel } from '../intent/schemas/intent-source.schema'
5
+ import { EcoConfigService } from '../eco-configs/eco-config.service'
6
+ import { EcoLogMessage } from '../common/logging/eco-log-message'
7
+ import { IntentSource } from '../eco-configs/eco-config.types'
8
+ import { IntentCreatedLog } from '../contracts'
9
+ import { BlockTag } from 'viem'
10
+ import { WatchCreateIntentService } from '../watch/intent/watch-create-intent.service'
11
+ import { KernelAccountClientService } from '../transaction/smart-wallets/kernel/kernel-account-client.service'
12
+ import { IntentSourceAbi } from '@eco-foundation/routes-ts'
13
+
14
+ /**
15
+ * Service class for syncing any missing transactions for all the source intent contracts.
16
+ * When the module starts up, it will check for any transactions that have occured since the
17
+ * last recorded transaction in the database and what is on chain. Intended to fill any
18
+ * gap in transactions that may have been missed while the serivce was down.
19
+ */
20
+ @Injectable()
21
+ export class ChainSyncService implements OnApplicationBootstrap {
22
+ private logger = new Logger(ChainSyncService.name)
23
+
24
+ constructor(
25
+ @InjectModel(IntentSourceModel.name) private intentModel: Model<IntentSourceModel>,
26
+ private readonly kernelAccountClientService: KernelAccountClientService,
27
+ private readonly watchIntentService: WatchCreateIntentService,
28
+ private ecoConfigService: EcoConfigService,
29
+ ) {}
30
+
31
+ async onApplicationBootstrap() {
32
+ this.logger.debug(
33
+ EcoLogMessage.fromDefault({
34
+ message: `ChainSyncService:OnApplicationBootstrap`,
35
+ }),
36
+ )
37
+ await this.syncTxs()
38
+ }
39
+
40
+ /**
41
+ * Syncs all the missing transactions for all the source intent contracts.
42
+ */
43
+ async syncTxs() {
44
+ const missingTxsTasks = this.ecoConfigService.getIntentSources().map((source) => {
45
+ return this.syncTxsPerSource(source)
46
+ })
47
+
48
+ await Promise.all(missingTxsTasks)
49
+ }
50
+
51
+ /**
52
+ * Returns the missing transactions for a source intent contract
53
+ *
54
+ * @param source the source intent to get the missing transactions for
55
+ * @returns
56
+ */
57
+ async syncTxsPerSource(source: IntentSource) {
58
+ const createIntentLogs = await this.getMissingTxs(source)
59
+ if (createIntentLogs.length === 0) {
60
+ return
61
+ }
62
+
63
+ return this.watchIntentService.addJob(source)(createIntentLogs)
64
+ }
65
+
66
+ /**
67
+ * Gets the missing transactions for a source intent contract by checking the last processed
68
+ * event in the database and querying the chain for events from that block number.
69
+ *
70
+ * TODO: need to add pagination for large amounts of missing transactions with subgraphs at 10k events
71
+ * @param source the source intent to get missing transactions for
72
+ * @returns
73
+ */
74
+ async getMissingTxs(source: IntentSource): Promise<IntentCreatedLog[]> {
75
+ const client = await this.kernelAccountClientService.getClient(source.chainID)
76
+
77
+ const lastRecordedTx = await this.getLastRecordedTx(source)
78
+ const fromBlock: bigint =
79
+ lastRecordedTx.length > 0
80
+ ? BigInt(lastRecordedTx[0].event.blockNumber) + 1n //start search from next block
81
+ : 0n
82
+ const toBlock: BlockTag = 'latest'
83
+ const supportedChains = this.ecoConfigService.getSupportedChains()
84
+ const createIntentLogs = (
85
+ await client.getContractEvents({
86
+ address: source.sourceAddress,
87
+ abi: IntentSourceAbi,
88
+ eventName: 'IntentCreated',
89
+ args: {
90
+ prover: source.provers,
91
+ },
92
+ fromBlock,
93
+ toBlock,
94
+ })
95
+ ).filter((log) => supportedChains.includes(log.args.destination || 0n))
96
+
97
+ //todo clean out already fulfilled intents
98
+ if (createIntentLogs.length === 0) {
99
+ this.logger.log(
100
+ EcoLogMessage.fromDefault({
101
+ message: `No transactions found for source ${source.network} to sync from block ${fromBlock}`,
102
+ properties: {
103
+ chainID: source.chainID,
104
+ fromBlock,
105
+ },
106
+ }),
107
+ )
108
+ return []
109
+ }
110
+
111
+ // add the required source network and chain id to the logs
112
+ return createIntentLogs.map((log) => {
113
+ return {
114
+ ...log,
115
+ sourceNetwork: source.network,
116
+ sourceChainID: source.chainID,
117
+ } as unknown as IntentCreatedLog
118
+ })
119
+ }
120
+
121
+ /**
122
+ * Returns the last recorded transaction for a source intent contract.
123
+ *
124
+ * @param source the source intent to get the last recorded transaction for
125
+ * @returns
126
+ */
127
+ async getLastRecordedTx(source: IntentSource): Promise<IntentSourceModel[]> {
128
+ return await this.intentModel
129
+ .find({ 'event.sourceChainID': source.chainID })
130
+ .sort({ 'event.blockNumber': -1 })
131
+ .limit(1)
132
+ .exec()
133
+ }
134
+ }