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,167 @@
1
+ import { createMock, DeepMocked } from '@golevelup/ts-jest'
2
+ import { EcoConfigService } from '../../eco-configs/eco-config.service'
3
+ import { Test, TestingModule } from '@nestjs/testing'
4
+ import { ProofService } from '../../prover/proof.service'
5
+ import { RetryInfeasableIntentsService } from '@/intervals/retry-infeasable-intents.service'
6
+ import { Queue } from 'bullmq'
7
+ import { getModelToken } from '@nestjs/mongoose'
8
+ import { Model } from 'mongoose'
9
+ import { IntentSourceModel } from '@/intent/schemas/intent-source.schema'
10
+ import { BullModule, getQueueToken } from '@nestjs/bullmq'
11
+ import { QUEUES } from '@/common/redis/constants'
12
+ import { Proofs } from '@/contracts'
13
+ import { Hex } from 'viem'
14
+
15
+ describe('RetryInfeasableIntentsService', () => {
16
+ let infeasableService: RetryInfeasableIntentsService
17
+ let proofService: DeepMocked<ProofService>
18
+ let ecoConfigService: DeepMocked<EcoConfigService>
19
+ let intervalQueue: DeepMocked<Queue>
20
+ let intentQueue: DeepMocked<Queue>
21
+ let intentSourceModel: DeepMocked<Model<IntentSourceModel>>
22
+
23
+ const mockLogDebug = jest.fn()
24
+ const mockLogLog = jest.fn()
25
+
26
+ beforeEach(async () => {
27
+ const chainMod: TestingModule = await Test.createTestingModule({
28
+ providers: [
29
+ RetryInfeasableIntentsService,
30
+ {
31
+ provide: getModelToken(IntentSourceModel.name),
32
+ useValue: createMock<Model<IntentSourceModel>>(),
33
+ },
34
+ { provide: ProofService, useValue: createMock<ProofService>() },
35
+ { provide: EcoConfigService, useValue: createMock<EcoConfigService>() },
36
+ ],
37
+ imports: [
38
+ BullModule.registerQueue({
39
+ name: QUEUES.INTERVAL.queue,
40
+ }),
41
+ BullModule.registerQueue({
42
+ name: QUEUES.SOURCE_INTENT.queue,
43
+ }),
44
+ ],
45
+ })
46
+ .overrideProvider(getQueueToken(QUEUES.INTERVAL.queue))
47
+ .useValue(createMock<Queue>())
48
+ .overrideProvider(getQueueToken(QUEUES.SOURCE_INTENT.queue))
49
+ .useValue(createMock<Queue>())
50
+ .compile()
51
+
52
+ //turn off the services from logging durring testing
53
+ chainMod.useLogger(false)
54
+ infeasableService = chainMod.get(RetryInfeasableIntentsService)
55
+ proofService = chainMod.get(ProofService)
56
+ ecoConfigService = chainMod.get(EcoConfigService)
57
+ intentSourceModel = chainMod.get(getModelToken(IntentSourceModel.name))
58
+ intervalQueue = chainMod.get(getQueueToken(QUEUES.INTERVAL.queue))
59
+ intentQueue = chainMod.get(getQueueToken(QUEUES.SOURCE_INTENT.queue))
60
+
61
+ infeasableService['logger'].debug = mockLogDebug
62
+ infeasableService['logger'].log = mockLogLog
63
+ })
64
+
65
+ afterEach(async () => {
66
+ jest.restoreAllMocks()
67
+ mockLogDebug.mockClear()
68
+ mockLogLog.mockClear()
69
+ })
70
+
71
+ describe('on startup', () => {
72
+ const mockInternals = {
73
+ retryInfeasableIntents: {
74
+ repeatOpts: {
75
+ every: 10000,
76
+ },
77
+ jobTemplate: {
78
+ name: 'retry-infeasable-intents',
79
+ data: {},
80
+ },
81
+ },
82
+ }
83
+ beforeEach(async () => {
84
+ ecoConfigService.getIntervals.mockReturnValue(mockInternals as any)
85
+ })
86
+
87
+ it('should set intentJobConfig', async () => {
88
+ await infeasableService.onModuleInit()
89
+ expect(ecoConfigService.getIntervals).toHaveBeenCalledTimes(1)
90
+ })
91
+
92
+ it('should set upsertJobScheduler', async () => {
93
+ await infeasableService.onApplicationBootstrap()
94
+ expect(ecoConfigService.getIntervals).toHaveBeenCalledTimes(1)
95
+ expect(intervalQueue.upsertJobScheduler).toHaveBeenCalledTimes(1)
96
+ expect(intervalQueue.upsertJobScheduler).toHaveBeenCalledWith(
97
+ QUEUES.INTERVAL.jobs.RETRY_INFEASABLE_INTENTS,
98
+ { ...mockInternals.retryInfeasableIntents.repeatOpts, immediately: true },
99
+ {
100
+ ...mockInternals.retryInfeasableIntents.jobTemplate,
101
+ name: QUEUES.INTERVAL.jobs.retry_infeasable_intents,
102
+ },
103
+ )
104
+ })
105
+ })
106
+
107
+ describe('on retryInfeasableIntents', () => {
108
+ let mockGetInfeasableIntents = jest.fn()
109
+ const mockModels = [
110
+ { intent: { hash: 'hash1', logIndex: 1 } },
111
+ { intent: { hash: 'hash2', logIndex: 2 } },
112
+ ]
113
+ beforeEach(async () => {
114
+ infeasableService['getInfeasableIntents'] = mockGetInfeasableIntents
115
+ mockGetInfeasableIntents.mockResolvedValue(mockModels)
116
+ })
117
+
118
+ it('should log models retrieved', async () => {
119
+ await infeasableService.retryInfeasableIntents()
120
+ expect(mockLogDebug).toHaveBeenCalledTimes(1)
121
+ expect(mockLogDebug).toHaveBeenCalledWith({
122
+ msg: 'retryInfeasableIntents',
123
+ models: mockModels,
124
+ })
125
+ })
126
+
127
+ it('should add every model to the queue', async () => {
128
+ const addSpy = jest.spyOn(intentQueue, 'add')
129
+ await infeasableService.retryInfeasableIntents()
130
+ expect(addSpy).toHaveBeenCalledTimes(2)
131
+ })
132
+ })
133
+
134
+ describe('getInfeasableIntents', () => {
135
+ it('should fetch intents with status INFEASABLE and valid expiration for Hyperlane proofs', async () => {
136
+ const minDateHyper = new Date('2022-01-01')
137
+ const minDateStorage = new Date('2022-01-02')
138
+ const proverHyper: Hex[] = ['0x1a', '0x2a']
139
+ const proverStorage: Hex[] = ['0x3b', '0x4b']
140
+ const mockGetProofMinimumDate = jest
141
+ .spyOn(proofService, 'getProofMinimumDate')
142
+ .mockImplementation((proof) => (proof == Proofs.Hyperlane ? minDateHyper : minDateStorage))
143
+ const mockGetProvers = jest
144
+ .spyOn(proofService, 'getProvers')
145
+ .mockImplementation((proof) => (proof == Proofs.Hyperlane ? proverHyper : proverStorage))
146
+
147
+ await infeasableService['getInfeasableIntents']()
148
+
149
+ expect(intentSourceModel.find).toHaveBeenCalledWith({
150
+ status: 'INFEASABLE',
151
+ $or: [
152
+ {
153
+ 'intent.expiration': { $gt: minDateHyper },
154
+ 'intent.prover': { $in: proverHyper },
155
+ },
156
+ {
157
+ 'intent.expiration': { $gt: minDateStorage },
158
+ 'intent.prover': { $in: proverStorage },
159
+ },
160
+ ],
161
+ })
162
+
163
+ expect(mockGetProofMinimumDate).toHaveBeenCalledTimes(2)
164
+ expect(mockGetProvers).toHaveBeenCalledTimes(2)
165
+ })
166
+ })
167
+ })
File without changes
@@ -0,0 +1,12 @@
1
+ import { KmsService } from '@/kms/kms.service'
2
+ import { Module } from '@nestjs/common'
3
+
4
+ @Module({
5
+ imports: [],
6
+ providers: [KmsService],
7
+ exports: [KmsService],
8
+ })
9
+ /**
10
+ * A module for dealing with the aws kms service.
11
+ */
12
+ export class KmsModule {}
@@ -0,0 +1,65 @@
1
+ import { EcoError } from '@/common/errors/eco-error'
2
+ import { EcoLogMessage } from '@/common/logging/eco-log-message'
3
+ import { obscureCenter } from '@/common/utils/strings'
4
+ import { EcoConfigService } from '@/eco-configs/eco-config.service'
5
+ import { Injectable, Logger, OnModuleInit } from '@nestjs/common'
6
+ import { Signer } from '@web3-kms-signer/core'
7
+ import { KMSProviderAWS } from '@web3-kms-signer/kms-provider-aws'
8
+ import { KMSWallets } from '@web3-kms-signer/kms-wallets'
9
+ import { getAddress as viemGetAddress, Hex } from 'viem'
10
+
11
+ /**
12
+ * A service class that initializes the kms signer and provides for signing of messages.
13
+ * @see {@link SignerKmsService}
14
+ */
15
+ @Injectable()
16
+ export class KmsService implements OnModuleInit {
17
+ private logger = new Logger(KmsService.name)
18
+ private keyID: string
19
+ wallets: KMSWallets
20
+ signer: Signer
21
+ constructor(private readonly ecoConfigService: EcoConfigService) {}
22
+
23
+ async onModuleInit() {
24
+ const kmsConfig = this.ecoConfigService.getKmsConfig()
25
+ if (!kmsConfig) {
26
+ throw EcoError.KmsCredentialsError(kmsConfig)
27
+ }
28
+ this.keyID = kmsConfig.keyID
29
+
30
+ const provider = new KMSProviderAWS({
31
+ region: kmsConfig.region,
32
+ })
33
+ this.wallets = new KMSWallets(provider)
34
+
35
+ // Dont need chainId because transactions eip1559, already hash the chainID on signature in viem
36
+ // Basic signs do need chainID for eip 155
37
+ this.signer = new Signer(this.wallets) //, chainId)
38
+
39
+ this.logger.log(
40
+ EcoLogMessage.fromDefault({
41
+ message: `KmsService initialized`,
42
+ properties: {
43
+ kmsAddress: await this.getAddress(),
44
+ kmsKeyId: obscureCenter(this.getKmsKeyId()),
45
+ },
46
+ }),
47
+ )
48
+ }
49
+
50
+ /**
51
+ * Returns the address as hex of the KMS signer.
52
+ * @returns the KMS eth address
53
+ */
54
+ async getAddress(): Promise<Hex> {
55
+ return viemGetAddress(await this.wallets.getAddressHex(this.keyID))
56
+ }
57
+
58
+ /**
59
+ * Returns the KMS key ID that this service uses to sign
60
+ * @returns the KMS key ID
61
+ */
62
+ getKmsKeyId(): string {
63
+ return this.keyID
64
+ }
65
+ }
@@ -0,0 +1,60 @@
1
+ const mockGetAddress = jest.fn()
2
+ import { Test, TestingModule } from '@nestjs/testing'
3
+ import { EcoConfigService } from '@/eco-configs/eco-config.service'
4
+ import { EcoError } from '@/common/errors/eco-error'
5
+ import { KMSWallets } from '@web3-kms-signer/kms-wallets'
6
+ import { Signer } from '@web3-kms-signer/core'
7
+ import { Logger } from '@nestjs/common'
8
+ import { KmsService } from '@/kms/kms.service'
9
+ import { createMock, DeepMocked } from '@golevelup/ts-jest'
10
+
11
+ jest.mock('viem', () => {
12
+ return {
13
+ ...jest.requireActual('viem'),
14
+ getAddress: mockGetAddress,
15
+ }
16
+ })
17
+ describe('KmsService', () => {
18
+ let service: KmsService
19
+ let ecoConfigService: DeepMocked<EcoConfigService>
20
+ let logger: Logger
21
+
22
+ beforeEach(async () => {
23
+ const module: TestingModule = await Test.createTestingModule({
24
+ providers: [
25
+ KmsService,
26
+ {
27
+ provide: EcoConfigService,
28
+ useValue: createMock<EcoConfigService>(),
29
+ },
30
+ ],
31
+ }).compile()
32
+
33
+ service = module.get<KmsService>(KmsService)
34
+ ecoConfigService = module.get(EcoConfigService)
35
+ logger = new Logger()
36
+
37
+ mockGetAddress.mockClear()
38
+ })
39
+
40
+ it('should be defined', () => {
41
+ expect(service).toBeDefined()
42
+ })
43
+
44
+ it('should throw an error if KMS config is missing', async () => {
45
+ jest.spyOn(ecoConfigService, 'getKmsConfig').mockReturnValue(null as any)
46
+ await expect(service.onModuleInit()).rejects.toThrow(EcoError.KmsCredentialsError(null as any))
47
+ })
48
+
49
+ it('should call viem to checksum and verify address', async () => {
50
+ const ma = '0x123'
51
+ const mockGetHex = jest.fn().mockResolvedValue(ma)
52
+ mockGetAddress.mockResolvedValue(ma)
53
+ service.wallets = {
54
+ getAddressHex: mockGetHex,
55
+ } as any
56
+ expect(await service.getAddress()).toBe(ma)
57
+ expect(mockGetAddress).toHaveBeenCalledTimes(1)
58
+ expect(mockGetHex).toHaveBeenCalledTimes(1)
59
+ })
60
+ })
@@ -0,0 +1,229 @@
1
+ import { Queue } from 'bullmq'
2
+ import { formatUnits } from 'viem'
3
+ import { table } from 'table'
4
+ import { EcoLogMessage } from '@/common/logging/eco-log-message'
5
+ import {
6
+ LiquidityManagerJob,
7
+ LiquidityManagerJobManager,
8
+ } from '@/liquidity-manager/jobs/liquidity-manager.job'
9
+ import { LiquidityManagerJobName } from '@/liquidity-manager/queues/liquidity-manager.queue'
10
+ import { LiquidityManagerProcessor } from '@/liquidity-manager/processors/eco-protocol-intents.processor'
11
+ import { shortAddr } from '@/liquidity-manager/utils/address'
12
+ import { removeJobSchedulers } from '@/bullmq/utils/queue'
13
+ import {
14
+ RebalanceQuote,
15
+ RebalanceRequest,
16
+ TokenDataAnalyzed,
17
+ } from '@/liquidity-manager/types/types'
18
+
19
+ /**
20
+ * A cron job that checks token balances, logs information, and attempts to rebalance deficits.
21
+ */
22
+ export class CheckBalancesCronJobManager extends LiquidityManagerJobManager {
23
+ static readonly jobSchedulerName = 'job-scheduler-check-balances'
24
+
25
+ /**
26
+ * Starts the CheckBalancesCronJob by removing existing repeatable jobs and adding a new one to the queue.
27
+ * @param queue - The job queue to add the job to.
28
+ * @param interval - Interval duration in which the job is repeated
29
+ */
30
+ static async start(queue: Queue, interval: number): Promise<void> {
31
+ await removeJobSchedulers(queue, LiquidityManagerJobName.CHECK_BALANCES)
32
+
33
+ await queue.upsertJobScheduler(
34
+ CheckBalancesCronJobManager.jobSchedulerName,
35
+ { every: interval },
36
+ {
37
+ name: LiquidityManagerJobName.CHECK_BALANCES,
38
+ opts: {
39
+ removeOnComplete: true,
40
+ },
41
+ },
42
+ )
43
+ }
44
+
45
+ /**
46
+ * Type guard to check if the given job is an instance of CheckBalancesCronJob.
47
+ * @param job - The job to check.
48
+ * @returns True if the job is a CheckBalancesCronJob.
49
+ */
50
+ is(job: LiquidityManagerJob): boolean {
51
+ return job.name === LiquidityManagerJobName.CHECK_BALANCES
52
+ }
53
+
54
+ /**
55
+ * Processes the CheckBalancesCronJob by analyzing token balances, logging the results, and rebalancing deficits.
56
+ * @param job - The CheckBalancesCronJob instance to process.
57
+ * @param processor - The LiquidityManagerProcessor instance used for processing.
58
+ */
59
+ async process(job: LiquidityManagerJob, processor: LiquidityManagerProcessor): Promise<void> {
60
+ const { deficit, surplus, items } = await processor.liquidityManagerService.analyzeTokens()
61
+
62
+ processor.logger.log(
63
+ EcoLogMessage.fromDefault({
64
+ message: `CheckBalancesCronJob: process`,
65
+ properties: {
66
+ surplus: surplus.total,
67
+ deficit: deficit.total,
68
+ },
69
+ }),
70
+ )
71
+
72
+ processor.logger.log(this.displayTokenTable(items))
73
+
74
+ if (!deficit.total) {
75
+ processor.logger.log(
76
+ EcoLogMessage.fromDefault({
77
+ message: `CheckBalancesCronJob: No deficits found`,
78
+ }),
79
+ )
80
+ return
81
+ }
82
+
83
+ const rebalances: RebalanceRequest[] = []
84
+
85
+ for (const deficitToken of deficit.items) {
86
+ const rebalancingQuotes = await processor.liquidityManagerService.getOptimizedRebalancing(
87
+ deficitToken,
88
+ surplus.items,
89
+ )
90
+
91
+ if (!rebalancingQuotes) {
92
+ processor.logger.debug(
93
+ EcoLogMessage.fromDefault({
94
+ message: 'CheckBalancesCronJob: No rebalancing quotes found',
95
+ properties: {
96
+ deficitToken,
97
+ },
98
+ }),
99
+ )
100
+ continue
101
+ }
102
+
103
+ this.updateGroupBalances(processor, surplus.items, rebalancingQuotes)
104
+
105
+ const rebalanceRequest = { token: deficitToken, quotes: rebalancingQuotes }
106
+
107
+ // Store rebalance request on DB
108
+ await processor.liquidityManagerService.storeRebalancing(rebalanceRequest)
109
+
110
+ rebalances.push(rebalanceRequest)
111
+ }
112
+
113
+ processor.logger.log(this.displayRebalancingTable(rebalances))
114
+
115
+ await processor.liquidityManagerService.startRebalancing(rebalances)
116
+ }
117
+
118
+ /**
119
+ * Handles job failures by logging the error.
120
+ * @param job - The job that failed.
121
+ * @param processor - The processor handling the job.
122
+ * @param error - The error that occurred.
123
+ */
124
+ onFailed(job: LiquidityManagerJob, processor: LiquidityManagerProcessor, error: unknown) {
125
+ processor.logger.error(
126
+ EcoLogMessage.fromDefault({
127
+ message: `CheckBalancesCronJob: Failed`,
128
+ properties: { error: (error as any)?.message ?? error },
129
+ }),
130
+ )
131
+ }
132
+
133
+ /**
134
+ * Displays a table of token data analysis.
135
+ * @param items - The token data to display.
136
+ * @returns A formatted table as a string.
137
+ */
138
+ private displayTokenTable(items: TokenDataAnalyzed[]) {
139
+ const formatter = new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 }).format
140
+
141
+ const header = ['Chain ID', 'Address', 'Balance', 'Target', 'Range', 'State']
142
+ const cells = items.map((item) => {
143
+ const format = (value: bigint) =>
144
+ formatter(parseFloat(formatUnits(value, item.balance.decimals)))
145
+ return [
146
+ item.config.chainId,
147
+ item.config.address,
148
+ format(item.analysis.balance.current),
149
+ format(item.analysis.balance.target),
150
+ `${format(item.analysis.balance.minimum)} - ${format(item.analysis.balance.maximum)}`,
151
+ item.analysis.state,
152
+ ]
153
+ })
154
+
155
+ return table([header, ...cells])
156
+ }
157
+
158
+ /**
159
+ * Displays a table of the rebasing data.
160
+ * @param items - The token data to display.
161
+ * @returns A formatted table as a string.
162
+ */
163
+ private displayRebalancingTable(items: RebalanceRequest[]) {
164
+ // Skip if no rebalancing quotes are found.
165
+ if (!items.length) return
166
+
167
+ const formatter = new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 }).format
168
+ const slippageFormatter = new Intl.NumberFormat('en-US', { maximumFractionDigits: 4 }).format
169
+ const format = (value: bigint, decimals: number) =>
170
+ formatter(parseFloat(formatUnits(value, decimals)))
171
+
172
+ const header = [
173
+ 'Token Out',
174
+ 'Chain Out',
175
+ 'Token In',
176
+ 'Chain In',
177
+ 'Current Balance',
178
+ 'Target Balance',
179
+ 'Strategy',
180
+ 'Amount In',
181
+ 'Amount Out',
182
+ 'Slippage',
183
+ ]
184
+ const cells = items
185
+ .flatMap((item) => item.quotes)
186
+ .map((quote) => {
187
+ return [
188
+ shortAddr(quote.tokenOut.config.address),
189
+ quote.tokenOut.config.chainId,
190
+ shortAddr(quote.tokenIn.config.address),
191
+ quote.tokenIn.config.chainId,
192
+ format(quote.tokenOut.balance.balance, quote.tokenOut.balance.decimals),
193
+ quote.tokenOut.config.targetBalance,
194
+ quote.strategy,
195
+ format(quote.amountIn, quote.tokenIn.balance.decimals),
196
+ format(quote.amountOut, quote.tokenOut.balance.decimals),
197
+ slippageFormatter(quote.slippage * 100) + '%',
198
+ ]
199
+ })
200
+
201
+ return table([header, ...cells], { columns: [{ width: 48 }] })
202
+ }
203
+
204
+ /**
205
+ * Updates the group balances after rebalancing quotes are received.
206
+ * @param processor - The LiquidityManagerProcessor instance used for processing.
207
+ * @param items - The list of token data analyzed.
208
+ * @param rebalancingQuotes - The quotes received for rebalancing.
209
+ */
210
+ private updateGroupBalances(
211
+ processor: LiquidityManagerProcessor,
212
+ items: TokenDataAnalyzed[],
213
+ rebalancingQuotes: RebalanceQuote[],
214
+ ) {
215
+ for (const quote of rebalancingQuotes) {
216
+ // Iterate through each rebalancing quote.
217
+ const token = items.find(
218
+ // Find the matching token in the items list.
219
+ (item) =>
220
+ item.config.address === quote.tokenIn.config.address &&
221
+ item.config.chainId === quote.tokenIn.config.chainId,
222
+ )
223
+ if (!token) continue
224
+
225
+ token.balance.balance -= quote.amountIn // Deduct the amount from the balance.
226
+ token.analysis = processor.liquidityManagerService.analyzeToken(token) // Re-analyze the token balance.
227
+ }
228
+ }
229
+ }
@@ -0,0 +1,52 @@
1
+ /* eslint @typescript-eslint/no-unused-vars: 0 */
2
+
3
+ import { Job } from 'bullmq'
4
+ import {
5
+ LiquidityManagerQueueDataType,
6
+ LiquidityManagerJobName,
7
+ } from '@/liquidity-manager/queues/liquidity-manager.queue'
8
+
9
+ export type LiquidityManagerJob<
10
+ NameType extends LiquidityManagerJobName = LiquidityManagerJobName,
11
+ DataType extends LiquidityManagerQueueDataType = LiquidityManagerQueueDataType,
12
+ > = Job<DataType, unknown, NameType>
13
+
14
+ export abstract class LiquidityManagerJobManager<
15
+ Job extends LiquidityManagerJob = LiquidityManagerJob,
16
+ > {
17
+ /**
18
+ * Checks if the given job is of the specific type.
19
+ * @param job - The job to check.
20
+ * @returns A boolean indicating if the job is of the specific type.
21
+ */
22
+ is(job: Job): boolean {
23
+ throw new Error('Unimplemented function')
24
+ }
25
+
26
+ /**
27
+ * Processes the given job.
28
+ * @param job - The job to process.
29
+ * @param processor - The processor handling the job.
30
+ */
31
+ process(job: Job, processor: unknown): Promise<void> {
32
+ throw new Error('Unimplemented function')
33
+ }
34
+
35
+ /**
36
+ * Hook triggered when a job is completed.
37
+ * @param job - The job to process.
38
+ * @param processor - The processor handling the job.
39
+ */
40
+ onComplete(job: Job, processor: unknown): void {
41
+ // Placeholder method implementation
42
+ }
43
+
44
+ /**
45
+ * Hook triggered when a job fails.
46
+ * @param job - The job to process.
47
+ * @param processor - The processor handling the job.
48
+ */
49
+ onFailed(job: Job, processor: unknown, error: unknown): void {
50
+ // Placeholder method implementation
51
+ }
52
+ }
@@ -0,0 +1,61 @@
1
+ import { FlowChildJob, Job } from 'bullmq'
2
+ import { EcoLogMessage } from '@/common/logging/eco-log-message'
3
+ import {
4
+ LiquidityManagerJob,
5
+ LiquidityManagerJobManager,
6
+ } from '@/liquidity-manager/jobs/liquidity-manager.job'
7
+ import { LiquidityManagerJobName } from '@/liquidity-manager/queues/liquidity-manager.queue'
8
+ import { LiquidityManagerProcessor } from '@/liquidity-manager/processors/eco-protocol-intents.processor'
9
+ import { serialize, Serialize } from '@/liquidity-manager/utils/serialize'
10
+ import { RebalanceRequest } from '@/liquidity-manager/types/types'
11
+
12
+ export type RebalanceJobData = {
13
+ network: string
14
+ rebalance: Serialize<RebalanceRequest>
15
+ }
16
+
17
+ type RebalanceJob = Job<RebalanceJobData, unknown, LiquidityManagerJobName.REBALANCE>
18
+
19
+ export class RebalanceJobManager extends LiquidityManagerJobManager<RebalanceJob> {
20
+ /**
21
+ * Type guard to check if the given job is an instance of RebalanceJob.
22
+ * @param job - The job to check.
23
+ * @returns True if the job is a RebalanceJob.
24
+ */
25
+ is(job: LiquidityManagerJob): job is RebalanceJob {
26
+ return job.name === LiquidityManagerJobName.REBALANCE
27
+ }
28
+
29
+ static createJob(rebalance: RebalanceRequest, queueName: string): FlowChildJob {
30
+ const data: RebalanceJobData = {
31
+ network: rebalance.token.config.chainId.toString(),
32
+ rebalance: serialize(rebalance),
33
+ }
34
+ return {
35
+ queueName,
36
+ data,
37
+ name: LiquidityManagerJobName.REBALANCE,
38
+ }
39
+ }
40
+
41
+ async process(job: LiquidityManagerJob, processor: LiquidityManagerProcessor): Promise<void> {
42
+ if (this.is(job)) {
43
+ return processor.liquidityManagerService.executeRebalancing(job.data)
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Handles job failures by logging the error.
49
+ * @param job - The job that failed.
50
+ * @param processor - The processor handling the job.
51
+ * @param error - The error that occurred.
52
+ */
53
+ onFailed(job: LiquidityManagerJob, processor: LiquidityManagerProcessor, error: Error) {
54
+ processor.logger.error(
55
+ EcoLogMessage.fromDefault({
56
+ message: `RebalanceJob: Failed`,
57
+ properties: { error: error.message },
58
+ }),
59
+ )
60
+ }
61
+ }
@@ -0,0 +1,29 @@
1
+ import { Module } from '@nestjs/common'
2
+ import { MongooseModule } from '@nestjs/mongoose'
3
+ import { BalanceModule } from '@/balance/balance.module'
4
+ import { TransactionModule } from '@/transaction/transaction.module'
5
+ import { LiquidityManagerQueue } from '@/liquidity-manager/queues/liquidity-manager.queue'
6
+ import { LiquidityManagerService } from '@/liquidity-manager/services/liquidity-manager.service'
7
+ import { LiquidityManagerProcessor } from '@/liquidity-manager/processors/eco-protocol-intents.processor'
8
+ import { LiquidityProviderService } from '@/liquidity-manager/services/liquidity-provider.service'
9
+ import { LiFiProviderService } from '@/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service'
10
+ import { RebalanceModel, RebalanceSchema } from '@/liquidity-manager/schemas/rebalance.schema'
11
+
12
+ @Module({
13
+ imports: [
14
+ BalanceModule,
15
+ TransactionModule,
16
+ LiquidityManagerQueue.init(),
17
+ LiquidityManagerQueue.initFlow(),
18
+
19
+ MongooseModule.forFeature([{ name: RebalanceModel.name, schema: RebalanceSchema }]),
20
+ ],
21
+ providers: [
22
+ LiquidityManagerService,
23
+ LiquidityManagerProcessor,
24
+ LiquidityProviderService,
25
+ LiFiProviderService,
26
+ ],
27
+ exports: [LiquidityManagerService],
28
+ })
29
+ export class LiquidityManagerModule {}