eco-solver 0.0.1-security → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

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 +117 -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,190 @@
1
+ import { createMock, DeepMocked } from '@golevelup/ts-jest'
2
+ import { ChainSyncService } from '../chain-sync.service'
3
+ import { WatchCreateIntentService } from '../../watch/intent/watch-create-intent.service'
4
+ import { EcoConfigService } from '../../eco-configs/eco-config.service'
5
+ import { Test, TestingModule } from '@nestjs/testing'
6
+ import { getModelToken } from '@nestjs/mongoose'
7
+ import { IntentSourceModel } from '../../intent/schemas/intent-source.schema'
8
+ import { Model } from 'mongoose'
9
+ import { Solver, IntentSource } from '../../eco-configs/eco-config.types'
10
+ import { entries } from 'lodash'
11
+ import { KernelAccountClientService } from '../../transaction/smart-wallets/kernel/kernel-account-client.service'
12
+ import { IntentSourceAbi } from '@eco-foundation/routes-ts'
13
+
14
+ describe('ChainSyncService', () => {
15
+ let chainSyncService: ChainSyncService
16
+ let accountService: DeepMocked<KernelAccountClientService>
17
+ let watchIntentService: DeepMocked<WatchCreateIntentService>
18
+ let ecoConfigService: DeepMocked<EcoConfigService>
19
+
20
+ beforeEach(async () => {
21
+ const chainMod: TestingModule = await Test.createTestingModule({
22
+ providers: [
23
+ ChainSyncService,
24
+ {
25
+ provide: KernelAccountClientService,
26
+ useValue: createMock<KernelAccountClientService>(),
27
+ },
28
+ { provide: WatchCreateIntentService, useValue: createMock<WatchCreateIntentService>() },
29
+ { provide: EcoConfigService, useValue: createMock<EcoConfigService>() },
30
+ {
31
+ provide: getModelToken(IntentSourceModel.name),
32
+ useValue: createMock<Model<IntentSourceModel>>(),
33
+ },
34
+ ],
35
+ }).compile()
36
+
37
+ chainSyncService = chainMod.get(ChainSyncService)
38
+ accountService = chainMod.get(KernelAccountClientService)
39
+ watchIntentService = chainMod.get(WatchCreateIntentService)
40
+ ecoConfigService = chainMod.get(EcoConfigService) as DeepMocked<EcoConfigService>
41
+ })
42
+
43
+ afterEach(async () => {
44
+ // restore the spy created with spyOn
45
+ jest.restoreAllMocks()
46
+ })
47
+
48
+ describe('on chain sync startup', () => {
49
+ it('should start a sync', async () => {
50
+ const mockSyncTxs = jest.fn()
51
+ chainSyncService.syncTxs = mockSyncTxs
52
+ await chainSyncService.onApplicationBootstrap()
53
+ expect(mockSyncTxs).toHaveBeenCalledTimes(1)
54
+ })
55
+ })
56
+
57
+ describe('on syncTxs', () => {
58
+ it('should start a sync for all source intent contracts', async () => {
59
+ const intentSources = [
60
+ { network: 'network1' },
61
+ { network: 'network2' },
62
+ { network: 'network3' },
63
+ ] as any
64
+ const mockSyncTxsPerSource = jest.fn()
65
+ chainSyncService.syncTxsPerSource = mockSyncTxsPerSource
66
+ ecoConfigService.getIntentSources.mockReturnValue(intentSources)
67
+
68
+ chainSyncService.syncTxs()
69
+ expect(mockSyncTxsPerSource).toHaveBeenCalledTimes(3)
70
+ expect(mockSyncTxsPerSource).toHaveBeenNthCalledWith(1, intentSources[0])
71
+ expect(mockSyncTxsPerSource).toHaveBeenNthCalledWith(2, intentSources[1])
72
+ expect(mockSyncTxsPerSource).toHaveBeenNthCalledWith(3, intentSources[2])
73
+ })
74
+ })
75
+
76
+ describe('on syncTxsPerSource', () => {
77
+ let mockGetContractEvents: jest.Mock
78
+
79
+ const intentSource = {
80
+ chainID: 123,
81
+ sourceAddress: '0x123',
82
+ network: 'network1',
83
+ provers: ['0x456', '0x789', '0xabc'],
84
+ } as unknown as IntentSource
85
+
86
+ const solvers = {
87
+ 123: {
88
+ inboxAddress: '0x456',
89
+ },
90
+ 456: {
91
+ inboxAddress: '0x789',
92
+ },
93
+ 789: {
94
+ inboxAddress: '0xabc',
95
+ },
96
+ } as any as Solver[]
97
+
98
+ const model = { event: { blockNumber: 50n, sourceChainID: intentSource.chainID } }
99
+ const supportedChains = Object.keys(solvers).map((key) => BigInt(key))
100
+ beforeEach(() => {
101
+ mockGetContractEvents = jest.fn().mockResolvedValue([])
102
+
103
+ accountService.getClient = jest.fn().mockReturnValue({
104
+ getContractEvents: mockGetContractEvents,
105
+ })
106
+
107
+ ecoConfigService.getSolvers.mockReturnValue(solvers)
108
+ })
109
+
110
+ it('should set fromBlock to 0x0 when no transactions in db', async () => {
111
+ await chainSyncService.syncTxsPerSource(intentSource)
112
+ expect(mockGetContractEvents).toHaveBeenCalledTimes(1)
113
+ expect(mockGetContractEvents).toHaveBeenCalledWith({
114
+ address: intentSource.sourceAddress,
115
+ abi: IntentSourceAbi,
116
+ eventName: 'IntentCreated',
117
+ args: {
118
+ prover: intentSource.provers,
119
+ },
120
+ fromBlock: 0n,
121
+ toBlock: 'latest',
122
+ })
123
+ })
124
+
125
+ it('should set fromBlock to the block of the db transaction', async () => {
126
+ chainSyncService['getLastRecordedTx'] = jest.fn().mockResolvedValueOnce([model])
127
+
128
+ await chainSyncService.syncTxsPerSource(intentSource)
129
+ expect(mockGetContractEvents).toHaveBeenCalledTimes(1)
130
+ expect(mockGetContractEvents).toHaveBeenCalledWith({
131
+ address: intentSource.sourceAddress,
132
+ abi: IntentSourceAbi,
133
+ eventName: 'IntentCreated',
134
+ args: {
135
+ prover: intentSource.provers,
136
+ },
137
+ fromBlock: model.event.blockNumber + 1n, // we search from the next block
138
+ toBlock: 'latest',
139
+ })
140
+ })
141
+
142
+ it('should log when no transfers exist since last db record', async () => {
143
+ chainSyncService['getLastRecordedTx'] = jest.fn().mockResolvedValueOnce([model])
144
+ const mockLog = jest.fn()
145
+ chainSyncService['logger'].log = mockLog
146
+ await chainSyncService.syncTxsPerSource(intentSource)
147
+ expect(mockGetContractEvents).toHaveBeenCalledTimes(1)
148
+ expect(mockLog).toHaveBeenCalledTimes(1)
149
+ // we search from the next block
150
+ const searchFromBlock = model.event.blockNumber + 1n
151
+ expect(mockLog).toHaveBeenCalledWith({
152
+ msg: `No transactions found for source ${intentSource.network} to sync from block ${searchFromBlock}`,
153
+ chainID: model.event.sourceChainID,
154
+ fromBlock: searchFromBlock,
155
+ })
156
+ })
157
+
158
+ it('should process all the txs that are to a supported destination since the last saved blockNumber', async () => {
159
+ const unsupportedChain = 1000n
160
+ chainSyncService['getLastRecordedTx'] = jest.fn().mockResolvedValueOnce([model])
161
+ ecoConfigService.getSupportedChains.mockReturnValue(supportedChains)
162
+ const logs = [
163
+ { msg: 'firstlog', args: { destination: supportedChains[0] } },
164
+ { msg: 'secondlog', args: { destination: supportedChains[1] } },
165
+ { msg: 'thirdlog', args: { destination: unsupportedChain } },
166
+ ]
167
+ const returnLogs = logs
168
+ .filter((log) => supportedChains.includes(log.args.destination))
169
+ .map((log) => {
170
+ return {
171
+ ...log,
172
+ sourceNetwork: intentSource.network,
173
+ sourceChainID: intentSource.chainID,
174
+ }
175
+ })
176
+ const mockProcessJob = jest.fn()
177
+ const mockAddJob = jest.fn(() => mockProcessJob)
178
+ watchIntentService.addJob = mockAddJob as any
179
+ mockGetContractEvents.mockResolvedValueOnce(logs)
180
+ ecoConfigService.getIntentSources.mockReturnValue([intentSource])
181
+
182
+ await chainSyncService.syncTxs()
183
+ expect(mockAddJob).toHaveBeenCalledTimes(1)
184
+ expect(mockProcessJob).toHaveBeenCalledTimes(1)
185
+ expect(mockAddJob).toHaveBeenCalledWith(intentSource)
186
+ expect(mockProcessJob).toHaveBeenCalledWith(returnLogs)
187
+ expect(returnLogs).toHaveLength(2)
188
+ })
189
+ })
190
+ })
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ extends: '../../.eslintrc.js',
3
+ rules: {
4
+ 'no-console': 'off',
5
+ },
6
+ }
@@ -0,0 +1,12 @@
1
+ import { BalanceService } from '@/balance/balance.service'
2
+ import { BalanceCommand } from '@/commander/balance/balance.command'
3
+ import { TransferCommandModule } from '@/commander/transfer/transfer-command.module'
4
+ import { CacheModule } from '@nestjs/cache-manager'
5
+ import { Module } from '@nestjs/common'
6
+
7
+ @Module({
8
+ imports: [CacheModule.register(), TransferCommandModule],
9
+ providers: [BalanceCommand, BalanceService],
10
+ exports: [BalanceCommand],
11
+ })
12
+ export class BalanceCommandModule {}
@@ -0,0 +1,73 @@
1
+ import { getAddress } from 'viem'
2
+ import { Command, Option } from 'nest-commander'
3
+ import { EcoConfigService } from '@/eco-configs/eco-config.service'
4
+ import { BalanceService } from '@/balance/balance.service'
5
+ import { KernelAccountClientService } from '@/transaction/smart-wallets/kernel/kernel-account-client.service'
6
+ import { jsonBigInt } from '@/commander/utils'
7
+ import { ClientCommand } from '@/commander/transfer/client.command'
8
+
9
+ @Command({
10
+ name: 'balance',
11
+ description: 'Displays the balance of the Kernel wallet',
12
+ })
13
+ export class BalanceCommand extends ClientCommand {
14
+ constructor(
15
+ protected readonly balanceService: BalanceService,
16
+ protected readonly kernelAccountClientService: KernelAccountClientService,
17
+ protected readonly ecoConfigService: EcoConfigService,
18
+ ) {
19
+ super(balanceService, kernelAccountClientService, ecoConfigService)
20
+ }
21
+
22
+ async run(passedParams: string[], options?: Record<string, any>): Promise<void> {
23
+ console.log(`Wallet address: ${await this.getWalletAddress()}`)
24
+ if (Object.values(options || {}).length === 0) {
25
+ console.log('No options provided, fetching all token data')
26
+ const data = await this.balanceService.getAllTokenData()
27
+ console.log(`Token data:`)
28
+ console.log(jsonBigInt(data))
29
+ return
30
+ }
31
+
32
+ if (options?.chainID && options?.token) {
33
+ console.log(`Fetching balance on ${options.chainID} for ${options.token}`)
34
+ const data = await this.balanceService.fetchTokenBalances(options.chainID, [options.token])
35
+
36
+ console.log(`Token data on chain : ${options.chainID}:`)
37
+ console.log(jsonBigInt(data))
38
+ return
39
+ }
40
+
41
+ if (options?.chainID) {
42
+ console.log(`Fetching all balances on ${options.chainID}`)
43
+ const data = await this.balanceService.fetchTokenBalancesForChain(options.chainID)
44
+ console.log(`Tokens data on chain : ${options.chainID}:`)
45
+ console.log(jsonBigInt(data))
46
+ }
47
+
48
+ console.log(`You must set the chainID and token to get the balance of a token`)
49
+ }
50
+
51
+ async getWalletAddress() {
52
+ const chains = this.ecoConfigService.getSupportedChains()
53
+ const client = await this.kernelAccountClientService.getClient(Number(chains[0]))
54
+ return client.kernelAccount.address
55
+ }
56
+
57
+ // 84532 0xAb1D243b07e99C91dE9E4B80DFc2B07a8332A2f7
58
+ @Option({
59
+ flags: '-c, --chainID <chainID>',
60
+ description: 'The chain ID for a token balance',
61
+ })
62
+ parseChainID(val: string) {
63
+ return Number(val)
64
+ }
65
+
66
+ @Option({
67
+ flags: '-t, --token <token>',
68
+ description: 'The token address to get the balance of',
69
+ })
70
+ parseToken(val: string) {
71
+ return getAddress(val)
72
+ }
73
+ }
@@ -0,0 +1,15 @@
1
+ import { CommanderAppModule } from '@/commander/commander-app.module'
2
+ import { CommandFactory } from 'nest-commander'
3
+ import { Logger } from 'nestjs-pino'
4
+
5
+ async function bootstrap() {
6
+ try {
7
+ const cmd = CommandFactory.createWithoutRunning(CommanderAppModule)
8
+ const lg = (await cmd).get(Logger)
9
+ ;(await cmd).useLogger(lg)
10
+ await CommandFactory.runApplication(await cmd)
11
+ } catch (e) {
12
+ console.error(e)
13
+ }
14
+ }
15
+ bootstrap()
@@ -0,0 +1,31 @@
1
+ import { BalanceCommandModule } from '@/commander/balance/balance-command.module'
2
+ import { EcoConfigCommand } from '@/commander/eco-config.command'
3
+ import { SafeCommandModule } from '@/commander/safe/safe-command.module'
4
+ import { TransferCommandModule } from '@/commander/transfer/transfer-command.module'
5
+ import { EcoConfigModule } from '@/eco-configs/eco-config.module'
6
+ import { EcoConfigService } from '@/eco-configs/eco-config.service'
7
+ import { Module } from '@nestjs/common'
8
+ import { LoggerModule } from 'nestjs-pino'
9
+
10
+ @Module({
11
+ imports: [
12
+ EcoConfigModule.withAWS(),
13
+ BalanceCommandModule,
14
+ SafeCommandModule,
15
+ TransferCommandModule,
16
+ LoggerModule.forRootAsync({
17
+ inject: [EcoConfigService],
18
+ useFactory: async (configService: EcoConfigService) => {
19
+ const loggerConfig = configService.getLoggerConfig()
20
+ return {
21
+ pinoHttp: {
22
+ ...loggerConfig.pinoConfig.pinoHttp,
23
+ level: 'warn',
24
+ },
25
+ }
26
+ },
27
+ }),
28
+ ],
29
+ providers: [EcoConfigCommand],
30
+ })
31
+ export class CommanderAppModule {}
@@ -0,0 +1,20 @@
1
+ import { EcoConfigService } from '@/eco-configs/eco-config.service'
2
+ import { Command, CommandRunner } from 'nest-commander'
3
+
4
+ @Command({
5
+ name: 'configs',
6
+ arguments: '[task]',
7
+ description: 'A parameter parse',
8
+ })
9
+ export class EcoConfigCommand extends CommandRunner {
10
+ constructor(private readonly configService: EcoConfigService) {
11
+ super()
12
+ }
13
+
14
+ async run(passedParams: string[], options?: Record<string, any>): Promise<void> {
15
+ console.log('CLI Params', passedParams)
16
+ console.log('CLI Options', options)
17
+ console.log('configService: ', this.configService.getSupportedChains())
18
+ return Promise.resolve(undefined)
19
+ }
20
+ }
@@ -0,0 +1,11 @@
1
+ import { SafeCommand } from '@/commander/safe/safe.command'
2
+ import { TransferCommandModule } from '@/commander/transfer/transfer-command.module'
3
+ import { CacheModule } from '@nestjs/cache-manager'
4
+ import { Module } from '@nestjs/common'
5
+
6
+ @Module({
7
+ imports: [CacheModule.register(), TransferCommandModule],
8
+ providers: [SafeCommand],
9
+ exports: [SafeCommand],
10
+ })
11
+ export class SafeCommandModule {}
@@ -0,0 +1,70 @@
1
+ import { getAddress } from 'viem'
2
+ import { Command, CommandRunner, Option } from 'nest-commander'
3
+ import { getExecutorTransferData } from '@/transaction/smart-wallets/kernel/create.kernel.account'
4
+ import { GLOBAL_CONSTANTS } from '@rhinestone/module-sdk'
5
+
6
+ @Command({
7
+ name: 'safe',
8
+ description:
9
+ 'Generates the transaction calldata for a safe transaction on the OwnableExecutor module',
10
+ })
11
+ export class SafeCommand extends CommandRunner {
12
+ constructor() {
13
+ super()
14
+ }
15
+
16
+ async run(passedParams: string[], options?: Record<string, any>): Promise<void> {
17
+ if (options?.to && options?.amount && options?.token && options?.kernel) {
18
+ console.log(
19
+ `Transfer:
20
+ amount: ${options.amount}
21
+ token ${options.token}
22
+ to ${options.to}
23
+ kernel ${options.kernel}`,
24
+ )
25
+ const data = getExecutorTransferData(options?.kernel, {
26
+ to: options.to,
27
+ amount: options.amount,
28
+ tokenAddress: options.token,
29
+ })
30
+ console.log(`OwnableExecutor transfer data: ${data}`)
31
+ console.log(
32
+ `Should execute data on OwnableExecutor contract: ${GLOBAL_CONSTANTS.OWNABLE_EXECUTOR_ADDRESS}`,
33
+ )
34
+ return
35
+ }
36
+ console.log('You must set the to, amount, token and kernelAddress to generate the calldata')
37
+ }
38
+
39
+ @Option({
40
+ flags: '-k, --kernel <kernel>',
41
+ description: 'The kernel wallet address for the executor to call, which it owns',
42
+ })
43
+ parseKernelAddress(val: string) {
44
+ return getAddress(val)
45
+ }
46
+
47
+ @Option({
48
+ flags: '-t, --to <to>',
49
+ description: 'The recipient of the transaction',
50
+ })
51
+ parseTo(val: string) {
52
+ return getAddress(val)
53
+ }
54
+
55
+ @Option({
56
+ flags: '-a, --amount <amount>',
57
+ description: 'The amount in the decimals of the token to transfer',
58
+ })
59
+ parseAmount(val: string) {
60
+ return BigInt(val)
61
+ }
62
+
63
+ @Option({
64
+ flags: '-tk, --token <token>',
65
+ description: 'The ERC20 token address to transfer',
66
+ })
67
+ parseToken(val: string) {
68
+ return getAddress(val)
69
+ }
70
+ }
@@ -0,0 +1,24 @@
1
+ import { CommandRunner } from 'nest-commander'
2
+ import { EcoConfigService } from '@/eco-configs/eco-config.service'
3
+ import { BalanceService } from '@/balance/balance.service'
4
+ import { KernelAccountClientService } from '@/transaction/smart-wallets/kernel/kernel-account-client.service'
5
+
6
+ export abstract class ClientCommand extends CommandRunner {
7
+ constructor(
8
+ protected readonly balanceService: BalanceService,
9
+ protected readonly kernelAccountClientService: KernelAccountClientService,
10
+ protected readonly ecoConfigService: EcoConfigService,
11
+ ) {
12
+ super()
13
+ }
14
+
15
+ async getClient(chainID?: number) {
16
+ return await this.kernelAccountClientService.getClient(Number(chainID || 0))
17
+ }
18
+
19
+ async getWalletAddress(chainID?: number) {
20
+ const chains = this.ecoConfigService.getSupportedChains()
21
+ const client = await this.kernelAccountClientService.getClient(Number(chains[chainID || 0]))
22
+ return client.kernelAccount.address
23
+ }
24
+ }
@@ -0,0 +1,26 @@
1
+ import { BalanceService } from '@/balance/balance.service'
2
+ import { TransferCommand } from '@/commander/transfer/transfer.command'
3
+ import { KmsService } from '@/kms/kms.service'
4
+ import { SignerKmsService } from '@/sign/signer-kms.service'
5
+ import { KernelAccountClientService } from '@/transaction/smart-wallets/kernel/kernel-account-client.service'
6
+ import { CacheModule } from '@nestjs/cache-manager'
7
+ import { Module } from '@nestjs/common'
8
+
9
+ @Module({
10
+ imports: [CacheModule.register()],
11
+ providers: [
12
+ TransferCommand,
13
+ KmsService,
14
+ SignerKmsService,
15
+ KernelAccountClientService,
16
+ BalanceService,
17
+ ],
18
+ exports: [
19
+ TransferCommand,
20
+ KmsService,
21
+ SignerKmsService,
22
+ KernelAccountClientService,
23
+ BalanceService,
24
+ ],
25
+ })
26
+ export class TransferCommandModule {}
@@ -0,0 +1,138 @@
1
+ import { encodeFunctionData, getAddress, Hex, erc20Abi, parseEther } from 'viem'
2
+ import { Command, CommandRunner, Option } from 'nest-commander'
3
+ import { KernelAccountClientService } from '@/transaction/smart-wallets/kernel/kernel-account-client.service'
4
+ import { BalanceService } from '@/balance/balance.service'
5
+
6
+ @Command({
7
+ name: 'transfer',
8
+ arguments: '<recipient>',
9
+ description:
10
+ 'Moves ERC20 tokens from the Kernel wallet to another address, all values are in decimal 6 format',
11
+ })
12
+ export class TransferCommand extends CommandRunner {
13
+ constructor(
14
+ private readonly kernelAccountClientService: KernelAccountClientService,
15
+ private readonly balanceService: BalanceService,
16
+ ) {
17
+ super()
18
+ }
19
+
20
+ async run(passedParams: string[], options?: Record<string, any>): Promise<void> {
21
+ console.log('CLI TransferCommand Params', passedParams)
22
+ const recipient = getAddress(passedParams[0])
23
+ console.log('Recipient', recipient)
24
+
25
+ if (options?.native && options?.chainID) {
26
+ console.log(`Transfering native tokens to ${recipient} with amount: ${options.native}`)
27
+ await this.transferNative(options.chainID, recipient, options.native)
28
+ return
29
+ }
30
+
31
+ if (options?.everything && options?.chainID) {
32
+ console.log(`Transfering all tokens to ${recipient}`)
33
+ await this.transferTokens(options.chainID, recipient)
34
+ return
35
+ }
36
+
37
+ if (options?.token && options?.amount && options?.chainID) {
38
+ console.log(
39
+ `Transfering token: ${options.token} to ${recipient} with amount: ${options.amount}`,
40
+ )
41
+ await this.transferToken(options.chainID, options.token, recipient, options.amount)
42
+ return
43
+ }
44
+ }
45
+
46
+ @Option({
47
+ flags: '-t, --token <token>',
48
+ description: 'The address of the token to transfer',
49
+ })
50
+ parseToken(val: string) {
51
+ return getAddress(val)
52
+ }
53
+
54
+ @Option({
55
+ flags: '-a, --amount <amount>',
56
+ description: 'The amount in the decimals of the token to transfer',
57
+ })
58
+ parseAmount(val: string) {
59
+ return BigInt(val)
60
+ }
61
+
62
+ @Option({
63
+ flags: '-c, --chainID <chainID>',
64
+ description: 'The chain ID for a token balance',
65
+ })
66
+ parseChainID(val: string) {
67
+ return Number(val)
68
+ }
69
+
70
+ @Option({
71
+ flags: '-e, --everything',
72
+ description: 'True if the transfer should be done for all tokens',
73
+ })
74
+ parseEverything(val: string) {
75
+ console.log('parseEverything', val)
76
+ return true
77
+ }
78
+
79
+ @Option({
80
+ flags: '-n, --native <native>',
81
+ description: 'The amount of native tokens to send, in normal eth format',
82
+ })
83
+ parseNative(val: string) {
84
+ console.log('parseNative', val)
85
+ return parseEther(val)
86
+ }
87
+
88
+ /**
89
+ * Transfers a token to a recipient
90
+ * @param chainID the chain id
91
+ * @param token the token address
92
+ * @param recipient the recipient address
93
+ * @param amount the amount to transfer, assumes in correct decimal format for that token
94
+ */
95
+ async transferToken(chainID: number, token: Hex, recipient: Hex, amount: bigint) {
96
+ const client = await this.kernelAccountClientService.getClient(chainID)
97
+ const transferFunctionData = encodeFunctionData({
98
+ abi: erc20Abi,
99
+ functionName: 'transfer',
100
+ args: [recipient, amount],
101
+ })
102
+ const receipt = await client.execute([
103
+ { to: token, data: transferFunctionData, value: BigInt(0) },
104
+ ])
105
+ console.log('Transfer Receipt', receipt)
106
+ await client.waitForTransactionReceipt({ hash: receipt, confirmations: 5 })
107
+ }
108
+
109
+ /**
110
+ * Sends all the tokens on a given chain to a recipient
111
+ * @param chainID the chain id
112
+ * @param recipient the recipient address
113
+ * @returns
114
+ */
115
+ async transferTokens(chainID: number, recipient: Hex) {
116
+ const tokens = await this.balanceService.fetchTokenBalancesForChain(chainID)
117
+ if (!tokens) {
118
+ console.log('No tokens found')
119
+ return
120
+ }
121
+ const filtered = Object.values(tokens).filter((token) => token.balance > BigInt(0))
122
+ for (const token of filtered) {
123
+ await this.transferToken(chainID, token.address, recipient, token.balance)
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Transfers native tokens to a recipient
129
+ * @param chainID the chain id
130
+ * @param recipient the recipient address
131
+ * @param amount the amount to transfer in wei format
132
+ */
133
+ async transferNative(chainID: number, recipient: Hex, amount: bigint) {
134
+ const client = await this.kernelAccountClientService.getClient(chainID)
135
+ const receipt = await client.execute([{ to: recipient, value: amount }])
136
+ console.log('Transfer Receipt', receipt)
137
+ }
138
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Stringify data with BigInt support
3
+ * @param data the data to stringify
4
+ * @returns
5
+ */
6
+ export function jsonBigInt(data: any) {
7
+ return JSON.stringify(data, (_, v) => (typeof v === 'bigint' ? v.toString() : v), 2)
8
+ }
@@ -0,0 +1,12 @@
1
+ import { Chain } from 'viem'
2
+ import { arbitrum as varbitrum } from 'viem/chains'
3
+
4
+ export const arbitrum: Chain = {
5
+ ...varbitrum,
6
+ rpcUrls: {
7
+ ...varbitrum.rpcUrls,
8
+ alchemy: {
9
+ http: ['https://arb-mainnet.g.alchemy.com/v2'],
10
+ },
11
+ },
12
+ }
@@ -0,0 +1,21 @@
1
+ import { Chain } from 'viem'
2
+ import { base as vbase, baseSepolia as vbases } from 'viem/chains'
3
+
4
+ export const base: Chain = {
5
+ ...vbase,
6
+ rpcUrls: {
7
+ ...vbase.rpcUrls,
8
+ alchemy: {
9
+ http: ['https://base-mainnet.g.alchemy.com/v2'],
10
+ },
11
+ },
12
+ }
13
+ export const baseSepolia: Chain = {
14
+ ...vbases,
15
+ rpcUrls: {
16
+ ...vbases.rpcUrls,
17
+ alchemy: {
18
+ http: ['https://base-sepolia.g.alchemy.com/v2'],
19
+ },
20
+ },
21
+ }