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.

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 +43 -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,117 @@
1
+ import { Logger } from '@nestjs/common'
2
+ import { OnWorkerEvent, WorkerHost } from '@nestjs/bullmq'
3
+ import { EcoLogMessage } from '@/common/logging/eco-log-message'
4
+ import {
5
+ LiquidityManagerJob,
6
+ LiquidityManagerJobManager,
7
+ } from '@/liquidity-manager/jobs/liquidity-manager.job'
8
+
9
+ /**
10
+ * Abstract class representing a base processor for liquidity manager jobs.
11
+ * @template Job - The type of the job.
12
+ * @template JobType - The constructor type of the job.
13
+ */
14
+ export abstract class BaseProcessor<
15
+ Job extends LiquidityManagerJob = LiquidityManagerJob,
16
+ JobManager extends LiquidityManagerJobManager<Job> = LiquidityManagerJobManager<Job>,
17
+ > extends WorkerHost {
18
+ public readonly logger: Logger
19
+
20
+ /**
21
+ * Constructs a new BaseProcessor.
22
+ * @param name - The name of the processor.
23
+ * @param jobManagers - The array of job managers.
24
+ */
25
+ constructor(
26
+ protected readonly name: string,
27
+ protected readonly jobManagers: JobManager[],
28
+ ) {
29
+ super()
30
+ this.logger = new Logger(name)
31
+ }
32
+
33
+ /**
34
+ * Processes a job.
35
+ * @param job - The job to process.
36
+ * @returns The result of the job execution.
37
+ */
38
+ process(job: Job) {
39
+ this.logger.debug(
40
+ EcoLogMessage.fromDefault({
41
+ message: `${this.name}.process()`,
42
+ properties: {
43
+ jobName: job.name,
44
+ },
45
+ }),
46
+ )
47
+
48
+ return this.execute(job, 'process')
49
+ }
50
+
51
+ /**
52
+ * Hook triggered when a job is completed.
53
+ * @param job - The job that was completed.
54
+ * @returns The result of the onCompleted hook from the job type.
55
+ */
56
+ @OnWorkerEvent('completed')
57
+ onCompleted(job: Job) {
58
+ this.logger.debug(
59
+ EcoLogMessage.fromDefault({
60
+ message: `${this.name}.onComplete()`,
61
+ properties: {
62
+ jobName: job.name,
63
+ },
64
+ }),
65
+ )
66
+
67
+ return this.execute(job, 'onComplete')
68
+ }
69
+
70
+ /**
71
+ * Hook triggered when a job fails.
72
+ * @param job - The job that failed.
73
+ * @param error - The error that caused the job to fail.
74
+ * @returns The result of the onFailed hook from the job type.
75
+ */
76
+ @OnWorkerEvent('failed')
77
+ onFailed(job: Job, error: Error) {
78
+ this.logger.debug(
79
+ EcoLogMessage.fromDefault({
80
+ message: `${this.name}.onFailed()`,
81
+ properties: {
82
+ jobName: job.name,
83
+ },
84
+ }),
85
+ )
86
+
87
+ return this.execute(job, 'onFailed', error)
88
+ }
89
+
90
+ /**
91
+ * Executes a method on the job type that matches the given job.
92
+ * @param job - The job to execute the method on.
93
+ * @param method - The method to execute.
94
+ * @param params - Additional parameters for the method.
95
+ * @returns The result of the method execution.
96
+ */
97
+ private execute(job: Job, method: 'process' | 'onFailed' | 'onComplete', ...params: unknown[]) {
98
+ for (const manager of this.jobManagers) {
99
+ // Process the job if it matches the job type
100
+ if (manager.is(job)) {
101
+ return (manager[method] as any)(job, this, ...params)
102
+ }
103
+ }
104
+
105
+ this.logger.debug(
106
+ EcoLogMessage.fromDefault({
107
+ message: `${this.name}: Unknown job type`,
108
+ properties: {
109
+ jobName: job.name,
110
+ method,
111
+ },
112
+ }),
113
+ )
114
+
115
+ return undefined
116
+ }
117
+ }
@@ -0,0 +1,34 @@
1
+ import { Injectable } from '@nestjs/common'
2
+ import { InjectQueue, Processor } from '@nestjs/bullmq'
3
+ import { BaseProcessor } from '@/liquidity-manager/processors/base.processor'
4
+ import { LiquidityManagerService } from '@/liquidity-manager/services/liquidity-manager.service'
5
+ import { RebalanceJobManager } from '@/liquidity-manager/jobs/rebalance.job'
6
+ import { CheckBalancesCronJobManager } from '@/liquidity-manager/jobs/check-balances-cron.job'
7
+ import {
8
+ LiquidityManagerQueue,
9
+ LiquidityManagerQueueType,
10
+ } from '@/liquidity-manager/queues/liquidity-manager.queue'
11
+
12
+ /**
13
+ * Processor for handling liquidity manager jobs.
14
+ * Extends the GroupedJobsProcessor to ensure jobs in the same group are not processed concurrently.
15
+ */
16
+ @Injectable()
17
+ @Processor(LiquidityManagerQueue.queueName)
18
+ export class LiquidityManagerProcessor extends BaseProcessor {
19
+ /**
20
+ * Constructs a new LiquidityManagerProcessor.
21
+ * @param queue - The queue to process jobs from.
22
+ * @param liquidityManagerService - The service for managing liquidity.
23
+ */
24
+ constructor(
25
+ @InjectQueue(LiquidityManagerQueue.queueName)
26
+ protected readonly queue: LiquidityManagerQueueType,
27
+ public readonly liquidityManagerService: LiquidityManagerService,
28
+ ) {
29
+ super(LiquidityManagerProcessor.name, [
30
+ new CheckBalancesCronJobManager(),
31
+ new RebalanceJobManager(),
32
+ ])
33
+ }
34
+ }
@@ -0,0 +1,103 @@
1
+ import { Logger } from '@nestjs/common'
2
+ import {
3
+ LiquidityManagerJob,
4
+ LiquidityManagerJobManager,
5
+ } from '@/liquidity-manager/jobs/liquidity-manager.job'
6
+ import { BaseProcessor } from '@/liquidity-manager/processors/base.processor'
7
+ import { Queue } from 'bullmq'
8
+ import { EcoLogMessage } from '@/common/logging/eco-log-message'
9
+ import { OnWorkerEvent } from '@nestjs/bullmq'
10
+
11
+ /**
12
+ * Abstract class representing a processor for grouped jobs.
13
+ * @template Job - The type of the job.
14
+ */
15
+ export abstract class GroupedJobsProcessor<
16
+ Job extends LiquidityManagerJob = LiquidityManagerJob,
17
+ JobManager extends LiquidityManagerJobManager<Job> = LiquidityManagerJobManager<Job>,
18
+ > extends BaseProcessor<Job, JobManager> {
19
+ public readonly logger: Logger
20
+ protected abstract readonly queue: Queue
21
+
22
+ protected readonly activeGroups = new Set<string>()
23
+
24
+ /**
25
+ * Constructs a new GroupedJobsProcessor.
26
+ * @param groupBy - The property to group jobs by.
27
+ * @param params - Additional parameters for the base processor.
28
+ */
29
+ constructor(
30
+ protected readonly groupBy: string,
31
+ ...params: ConstructorParameters<typeof BaseProcessor<Job, JobManager>>
32
+ ) {
33
+ super(...params)
34
+ }
35
+
36
+ /**
37
+ * Processes a job, ensuring that jobs in the same group are not processed concurrently.
38
+ * @param job - The job to process.
39
+ * @returns A promise that resolves to an object indicating if the job was delayed.
40
+ */
41
+ async process(job: Job) {
42
+ const group = job.data?.[this.groupBy] as string
43
+
44
+ if (group) {
45
+ if (this.activeGroups.has(group)) {
46
+ this.logger.debug(
47
+ EcoLogMessage.fromDefault({
48
+ message: 'Job delayed due to group concurrency',
49
+ properties: {
50
+ jobName: job.name,
51
+ group,
52
+ },
53
+ }),
54
+ )
55
+
56
+ await this.queue.add(job.name, job.data, {
57
+ ...job.opts,
58
+ delay: 5_000, // Delay for 5 seconds
59
+ })
60
+
61
+ return { delayed: true }
62
+ }
63
+
64
+ this.activeGroups.add(group)
65
+ }
66
+
67
+ return super.process(job)
68
+ }
69
+
70
+ /**
71
+ * Hook triggered when a job is completed.
72
+ * @param job - The job that was completed.
73
+ */
74
+ @OnWorkerEvent('completed')
75
+ onCompleted(job: Job) {
76
+ const returnvalue = job.returnvalue as object
77
+ if (returnvalue && 'delayed' in returnvalue && returnvalue.delayed) {
78
+ // Skip onCompleted hook if job got delayed
79
+ return
80
+ } else if (
81
+ this.groupBy in job.data &&
82
+ this.activeGroups.has(job.data[this.groupBy] as string)
83
+ ) {
84
+ this.activeGroups.delete(job.data[this.groupBy] as string)
85
+ }
86
+
87
+ return super.onCompleted(job)
88
+ }
89
+
90
+ /**
91
+ * Hook triggered when a job fails.
92
+ * @param job - The job that was completed.
93
+ * @param error - Error.
94
+ */
95
+ @OnWorkerEvent('failed')
96
+ onFailed(job: Job, error: Error) {
97
+ if (this.groupBy in job.data && this.activeGroups.has(job.data[this.groupBy] as string)) {
98
+ this.activeGroups.delete(job.data[this.groupBy] as string)
99
+ }
100
+
101
+ return super.onFailed(job, error)
102
+ }
103
+ }
@@ -0,0 +1,48 @@
1
+ import { Queue } from 'bullmq'
2
+ import { initBullMQ, initFlowBullMQ } from '@/bullmq/bullmq.helper'
3
+ import { CheckBalancesCronJobManager } from '@/liquidity-manager/jobs/check-balances-cron.job'
4
+
5
+ export enum LiquidityManagerJobName {
6
+ REBALANCE = 'REBALANCE',
7
+ CHECK_BALANCES = 'CHECK_BALANCES',
8
+ }
9
+
10
+ export type LiquidityManagerQueueDataType = { network: string; [k: string]: unknown }
11
+
12
+ export type LiquidityManagerQueueType = Queue<
13
+ LiquidityManagerQueueDataType,
14
+ unknown,
15
+ LiquidityManagerJobName
16
+ >
17
+
18
+ export class LiquidityManagerQueue {
19
+ public static readonly prefix = '{liquidity-manager}'
20
+ public static readonly queueName = LiquidityManagerQueue.name
21
+ public static readonly flowName = `flow-liquidity-manager`
22
+
23
+ constructor(private readonly queue: LiquidityManagerQueueType) {}
24
+
25
+ get name() {
26
+ return this.queue.name
27
+ }
28
+
29
+ static init() {
30
+ return initBullMQ(
31
+ { queue: this.queueName, prefix: LiquidityManagerQueue.prefix },
32
+ {
33
+ defaultJobOptions: {
34
+ removeOnFail: true,
35
+ removeOnComplete: true,
36
+ },
37
+ },
38
+ )
39
+ }
40
+
41
+ static initFlow() {
42
+ return initFlowBullMQ({ queue: this.flowName, prefix: LiquidityManagerQueue.prefix })
43
+ }
44
+
45
+ startCronJobs(interval: number) {
46
+ return CheckBalancesCronJobManager.start(this.queue, interval)
47
+ }
48
+ }
@@ -0,0 +1,32 @@
1
+ import { TokenData } from '@/liquidity-manager/types/types'
2
+ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
3
+ import { formatUnits, Hex } from 'viem'
4
+
5
+ @Schema()
6
+ export class RebalanceTokenModel {
7
+ @Prop({ required: true })
8
+ chainId: number
9
+
10
+ @Prop({ required: true })
11
+ tokenAddress: Hex
12
+
13
+ @Prop({ required: true })
14
+ currentBalance: number
15
+
16
+ @Prop({ required: true })
17
+ targetBalance: number
18
+
19
+ static fromTokenData(tokenData: TokenData): RebalanceTokenModel {
20
+ const currentBalance = parseFloat(
21
+ formatUnits(tokenData.balance.balance, tokenData.balance.decimals),
22
+ )
23
+ return {
24
+ chainId: tokenData.chainId,
25
+ tokenAddress: tokenData.config.address,
26
+ currentBalance,
27
+ targetBalance: tokenData.config.targetBalance,
28
+ }
29
+ }
30
+ }
31
+
32
+ export const RebalanceTokenSchema = SchemaFactory.createForClass(RebalanceTokenModel)
@@ -0,0 +1,32 @@
1
+ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
2
+ import { RebalanceTokenModel } from './rebalance-token.schema'
3
+ import { Strategy, StrategyContext } from '@/liquidity-manager/types/types'
4
+
5
+ @Schema({ timestamps: true })
6
+ export class RebalanceModel {
7
+ @Prop({ required: true })
8
+ tokenIn: RebalanceTokenModel
9
+
10
+ @Prop({ required: true })
11
+ tokenOut: RebalanceTokenModel
12
+
13
+ @Prop({ required: true })
14
+ amountIn: bigint
15
+
16
+ @Prop({ required: true })
17
+ amountOut: bigint
18
+
19
+ @Prop({ required: true })
20
+ slippage: number
21
+
22
+ @Prop({ required: true })
23
+ strategy: Strategy
24
+
25
+ @Prop({ required: false })
26
+ groupId?: string
27
+
28
+ @Prop({ required: true, type: Object })
29
+ context: StrategyContext
30
+ }
31
+
32
+ export const RebalanceSchema = SchemaFactory.createForClass(RebalanceModel)
@@ -0,0 +1,188 @@
1
+ import { Model } from 'mongoose'
2
+ import { InjectModel } from '@nestjs/mongoose'
3
+ import { InjectFlowProducer, InjectQueue } from '@nestjs/bullmq'
4
+ import { FlowProducer } from 'bullmq'
5
+ import { Injectable, OnApplicationBootstrap } from '@nestjs/common'
6
+ import { groupBy } from 'lodash'
7
+ import { v4 as uuid } from 'uuid'
8
+ import { BalanceService } from '@/balance/balance.service'
9
+ import { TokenState } from '@/liquidity-manager/types/token-state.enum'
10
+ import {
11
+ analyzeToken,
12
+ analyzeTokenGroup,
13
+ getGroupTotal,
14
+ getSortGroupByDiff,
15
+ } from '@/liquidity-manager/utils/token'
16
+ import {
17
+ LiquidityManagerQueue,
18
+ LiquidityManagerQueueType,
19
+ } from '@/liquidity-manager/queues/liquidity-manager.queue'
20
+ import { RebalanceJobData, RebalanceJobManager } from '@/liquidity-manager/jobs/rebalance.job'
21
+ import { LiquidityProviderService } from '@/liquidity-manager/services/liquidity-provider.service'
22
+ import { deserialize } from '@/liquidity-manager/utils/serialize'
23
+ import { LiquidityManagerConfig } from '@/eco-configs/eco-config.types'
24
+ import { EcoConfigService } from '@/eco-configs/eco-config.service'
25
+ import { RebalanceModel } from '@/liquidity-manager/schemas/rebalance.schema'
26
+ import { RebalanceTokenModel } from '@/liquidity-manager/schemas/rebalance-token.schema'
27
+ import {
28
+ RebalanceQuote,
29
+ RebalanceRequest,
30
+ TokenData,
31
+ TokenDataAnalyzed,
32
+ } from '@/liquidity-manager/types/types'
33
+
34
+ @Injectable()
35
+ export class LiquidityManagerService implements OnApplicationBootstrap {
36
+ private config: LiquidityManagerConfig
37
+ private readonly liquidityManagerQueue: LiquidityManagerQueue
38
+
39
+ constructor(
40
+ @InjectQueue(LiquidityManagerQueue.queueName)
41
+ queue: LiquidityManagerQueueType,
42
+ @InjectFlowProducer(LiquidityManagerQueue.flowName)
43
+ protected liquidityManagerFlowProducer: FlowProducer,
44
+ @InjectModel(RebalanceModel.name)
45
+ private readonly rebalanceModel: Model<RebalanceModel>,
46
+ public readonly balanceService: BalanceService,
47
+ private readonly ecoConfigService: EcoConfigService,
48
+ public readonly liquidityProviderManager: LiquidityProviderService,
49
+ ) {
50
+ this.liquidityManagerQueue = new LiquidityManagerQueue(queue)
51
+ }
52
+
53
+ onApplicationBootstrap() {
54
+ this.config = this.ecoConfigService.getLiquidityManager()
55
+ return this.liquidityManagerQueue.startCronJobs(this.config.intervalDuration)
56
+ }
57
+
58
+ async analyzeTokens() {
59
+ const tokens: TokenData[] = await this.balanceService.getAllTokenData()
60
+ const analysis: TokenDataAnalyzed[] = tokens.map((item) => ({
61
+ ...item,
62
+ analysis: this.analyzeToken(item),
63
+ }))
64
+
65
+ const groups = groupBy(analysis, (item) => item.analysis.state)
66
+ return {
67
+ items: analysis,
68
+ surplus: analyzeTokenGroup(groups[TokenState.SURPLUS] ?? []),
69
+ inrange: analyzeTokenGroup(groups[TokenState.IN_RANGE] ?? []),
70
+ deficit: analyzeTokenGroup(groups[TokenState.DEFICIT] ?? []),
71
+ }
72
+ }
73
+
74
+ analyzeToken(token: TokenData) {
75
+ return analyzeToken(token.config, token.balance, {
76
+ up: this.config.thresholds.surplus,
77
+ down: this.config.thresholds.deficit,
78
+ targetSlippage: this.config.targetSlippage,
79
+ })
80
+ }
81
+
82
+ /**
83
+ * Gets the optimized rebalancing for the deficit and surplus tokens.
84
+ * @dev The rebalancing is more efficient if done within the same chain.
85
+ * If it's not possible, other chains are considered.
86
+ * @param deficitToken
87
+ * @param surplusTokens
88
+ */
89
+ async getOptimizedRebalancing(
90
+ deficitToken: TokenDataAnalyzed,
91
+ surplusTokens: TokenDataAnalyzed[],
92
+ ) {
93
+ const swapQuotes = await this.getSwapQuotes(deficitToken, surplusTokens)
94
+
95
+ // Continue with swap quotes if possible
96
+ if (swapQuotes.length) return swapQuotes
97
+
98
+ return this.getRebalancingQuotes(deficitToken, surplusTokens)
99
+ }
100
+
101
+ startRebalancing(rebalances: RebalanceRequest[]) {
102
+ const jobs = rebalances.map((rebalance) =>
103
+ RebalanceJobManager.createJob(rebalance, this.liquidityManagerQueue.name),
104
+ )
105
+ return this.liquidityManagerFlowProducer.add({
106
+ name: 'rebalance-batch',
107
+ queueName: this.liquidityManagerQueue.name,
108
+ children: jobs,
109
+ })
110
+ }
111
+
112
+ async executeRebalancing(rebalanceData: RebalanceJobData) {
113
+ for (const quote of rebalanceData.rebalance.quotes) {
114
+ await this.liquidityProviderManager.execute(deserialize(quote))
115
+ }
116
+ }
117
+
118
+ async storeRebalancing(request: RebalanceRequest) {
119
+ const groupId = uuid()
120
+ for (const quote of request.quotes) {
121
+ await this.rebalanceModel.create({
122
+ groupId,
123
+ amountIn: quote.amountIn,
124
+ amountOut: quote.amountOut,
125
+ slippage: quote.slippage,
126
+ strategy: quote.strategy,
127
+ context: quote.context,
128
+ tokenIn: RebalanceTokenModel.fromTokenData(quote.tokenIn),
129
+ tokenOut: RebalanceTokenModel.fromTokenData(quote.tokenOut),
130
+ })
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Checks if a swap is possible between the deficit and surplus tokens.
136
+ * @dev swaps are possible if the deficit is compensated by the surplus of tokens in the same chain.
137
+ * @param deficitToken
138
+ * @param surplusTokens
139
+ * @private
140
+ */
141
+ private async getSwapQuotes(deficitToken: TokenDataAnalyzed, surplusTokens: TokenDataAnalyzed[]) {
142
+ const surplusTokensSameChain = surplusTokens.filter(
143
+ (token) => token.config.chainId === deficitToken.config.chainId,
144
+ )
145
+
146
+ return this.getRebalancingQuotes(deficitToken, surplusTokensSameChain)
147
+ }
148
+
149
+ /**
150
+ * Checks if a rebalancing is possible between the deficit and surplus tokens.
151
+ * @param deficitToken
152
+ * @param surplusTokens
153
+ * @private
154
+ */
155
+ private async getRebalancingQuotes(
156
+ deficitToken: TokenDataAnalyzed,
157
+ surplusTokens: TokenDataAnalyzed[],
158
+ ) {
159
+ const sortedSurplusTokens = getSortGroupByDiff(surplusTokens)
160
+ const surplusTokensTotal = getGroupTotal(sortedSurplusTokens)
161
+
162
+ if (deficitToken.analysis.diff > surplusTokensTotal) {
163
+ // Not enough surplus tokens to rebalance
164
+ return []
165
+ }
166
+
167
+ const quotes: RebalanceQuote[] = []
168
+ let currentBalance = deficitToken.analysis.balance.current
169
+
170
+ for (const surplusToken of sortedSurplusTokens) {
171
+ // Calculate the amount to swap
172
+ const swapAmount = Math.min(deficitToken.analysis.diff, surplusToken.analysis.diff)
173
+
174
+ const quote = await this.liquidityProviderManager.getQuote(
175
+ surplusToken,
176
+ deficitToken,
177
+ swapAmount,
178
+ )
179
+
180
+ quotes.push(quote)
181
+ currentBalance += quote.amountOut
182
+
183
+ if (currentBalance >= deficitToken.analysis.targetSlippage.min) break
184
+ }
185
+
186
+ return quotes
187
+ }
188
+ }
@@ -0,0 +1,25 @@
1
+ import { Injectable } from '@nestjs/common'
2
+ import { LiFiProviderService } from '@/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service'
3
+ import { RebalanceQuote, TokenData } from '@/liquidity-manager/types/types'
4
+
5
+ @Injectable()
6
+ export class LiquidityProviderService {
7
+ constructor(protected readonly liFiProvider: LiFiProviderService) {}
8
+
9
+ async getQuote(
10
+ tokenIn: TokenData,
11
+ tokenOut: TokenData,
12
+ swapAmount: number,
13
+ ): Promise<RebalanceQuote> {
14
+ return this.liFiProvider.getQuote(tokenIn, tokenOut, swapAmount)
15
+ }
16
+
17
+ async execute(quote: RebalanceQuote) {
18
+ switch (quote.strategy) {
19
+ case 'LiFi':
20
+ return this.liFiProvider.execute(quote)
21
+ default:
22
+ throw new Error(`Strategy not supported: ${quote.strategy}`)
23
+ }
24
+ }
25
+ }