eco-solver 0.0.1-security → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of eco-solver might be problematic. Click here for more details.
- package/.eslintignore +8 -0
- package/.eslintrc.js +24 -0
- package/.github/workflows/ci.yaml +38 -0
- package/.nvmrc +1 -0
- package/.prettierignore +3 -0
- package/.prettierrc +8 -0
- package/Dockerfile +11 -0
- package/LICENSE +21 -0
- package/README.md +29 -5
- package/config/default.ts +135 -0
- package/config/development.ts +95 -0
- package/config/preproduction.ts +17 -0
- package/config/production.ts +17 -0
- package/config/staging.ts +17 -0
- package/config/test.ts +7 -0
- package/index.js +43 -0
- package/jest.config.ts +14 -0
- package/nest-cli.json +8 -0
- package/package.json +115 -6
- package/src/api/api.module.ts +27 -0
- package/src/api/balance.controller.ts +41 -0
- package/src/api/quote.controller.ts +54 -0
- package/src/api/tests/balance.controller.spec.ts +113 -0
- package/src/api/tests/quote.controller.spec.ts +83 -0
- package/src/app.module.ts +74 -0
- package/src/balance/balance.module.ts +14 -0
- package/src/balance/balance.service.ts +230 -0
- package/src/balance/balance.ws.service.ts +104 -0
- package/src/balance/types.ts +16 -0
- package/src/bullmq/bullmq.helper.ts +41 -0
- package/src/bullmq/processors/eth-ws.processor.ts +47 -0
- package/src/bullmq/processors/inbox.processor.ts +55 -0
- package/src/bullmq/processors/interval.processor.ts +54 -0
- package/src/bullmq/processors/processor.module.ts +14 -0
- package/src/bullmq/processors/signer.processor.ts +41 -0
- package/src/bullmq/processors/solve-intent.processor.ts +73 -0
- package/src/bullmq/processors/tests/solve-intent.processor.spec.ts +3 -0
- package/src/bullmq/utils/queue.ts +22 -0
- package/src/chain-monitor/chain-monitor.module.ts +12 -0
- package/src/chain-monitor/chain-sync.service.ts +134 -0
- package/src/chain-monitor/tests/chain-sync.service.spec.ts +190 -0
- package/src/commander/.eslintrc.js +6 -0
- package/src/commander/balance/balance-command.module.ts +12 -0
- package/src/commander/balance/balance.command.ts +73 -0
- package/src/commander/command-main.ts +15 -0
- package/src/commander/commander-app.module.ts +31 -0
- package/src/commander/eco-config.command.ts +20 -0
- package/src/commander/safe/safe-command.module.ts +11 -0
- package/src/commander/safe/safe.command.ts +70 -0
- package/src/commander/transfer/client.command.ts +24 -0
- package/src/commander/transfer/transfer-command.module.ts +26 -0
- package/src/commander/transfer/transfer.command.ts +138 -0
- package/src/commander/utils.ts +8 -0
- package/src/common/chains/definitions/arbitrum.ts +12 -0
- package/src/common/chains/definitions/base.ts +21 -0
- package/src/common/chains/definitions/eco.ts +54 -0
- package/src/common/chains/definitions/ethereum.ts +22 -0
- package/src/common/chains/definitions/helix.ts +53 -0
- package/src/common/chains/definitions/mantle.ts +12 -0
- package/src/common/chains/definitions/optimism.ts +22 -0
- package/src/common/chains/definitions/polygon.ts +12 -0
- package/src/common/chains/supported.ts +26 -0
- package/src/common/chains/transport.ts +19 -0
- package/src/common/errors/eco-error.ts +155 -0
- package/src/common/events/constants.ts +3 -0
- package/src/common/events/viem.ts +22 -0
- package/src/common/logging/eco-log-message.ts +74 -0
- package/src/common/redis/constants.ts +55 -0
- package/src/common/redis/redis-connection-utils.ts +106 -0
- package/src/common/routes/constants.ts +3 -0
- package/src/common/utils/objects.ts +34 -0
- package/src/common/utils/strings.ts +49 -0
- package/src/common/utils/tests/objects.spec.ts +23 -0
- package/src/common/utils/tests/strings.spec.ts +22 -0
- package/src/common/viem/contracts.ts +25 -0
- package/src/common/viem/tests/utils.spec.ts +115 -0
- package/src/common/viem/utils.ts +78 -0
- package/src/contracts/ERC20.contract.ts +389 -0
- package/src/contracts/EntryPoint.V6.contract.ts +1309 -0
- package/src/contracts/KernelAccount.abi.ts +87 -0
- package/src/contracts/OwnableExecutor.abi.ts +128 -0
- package/src/contracts/SimpleAccount.contract.ts +524 -0
- package/src/contracts/inbox.ts +8 -0
- package/src/contracts/index.ts +9 -0
- package/src/contracts/intent-source.ts +55 -0
- package/src/contracts/interfaces/index.ts +1 -0
- package/src/contracts/interfaces/prover.interface.ts +22 -0
- package/src/contracts/prover.ts +9 -0
- package/src/contracts/tests/erc20.contract.spec.ts +59 -0
- package/src/contracts/utils.ts +31 -0
- package/src/decoder/decoder.interface.ts +3 -0
- package/src/decoder/tests/utils.spec.ts +36 -0
- package/src/decoder/utils.ts +24 -0
- package/src/decorators/cacheable.decorator.ts +48 -0
- package/src/eco-configs/aws-config.service.ts +75 -0
- package/src/eco-configs/eco-config.module.ts +44 -0
- package/src/eco-configs/eco-config.service.ts +220 -0
- package/src/eco-configs/eco-config.types.ts +278 -0
- package/src/eco-configs/interfaces/config-source.interface.ts +3 -0
- package/src/eco-configs/tests/aws-config.service.spec.ts +52 -0
- package/src/eco-configs/tests/eco-config.service.spec.ts +137 -0
- package/src/eco-configs/tests/utils.spec.ts +84 -0
- package/src/eco-configs/utils.ts +49 -0
- package/src/fee/fee.module.ts +10 -0
- package/src/fee/fee.service.ts +467 -0
- package/src/fee/tests/fee.service.spec.ts +909 -0
- package/src/fee/tests/utils.spec.ts +49 -0
- package/src/fee/types.ts +44 -0
- package/src/fee/utils.ts +23 -0
- package/src/flags/flags.module.ts +10 -0
- package/src/flags/flags.service.ts +112 -0
- package/src/flags/tests/flags.service.spec.ts +68 -0
- package/src/flags/utils.ts +22 -0
- package/src/health/constants.ts +1 -0
- package/src/health/health.controller.ts +23 -0
- package/src/health/health.module.ts +25 -0
- package/src/health/health.service.ts +40 -0
- package/src/health/indicators/balance.indicator.ts +196 -0
- package/src/health/indicators/eco-redis.indicator.ts +23 -0
- package/src/health/indicators/git-commit.indicator.ts +67 -0
- package/src/health/indicators/mongodb.indicator.ts +11 -0
- package/src/health/indicators/permission.indicator.ts +64 -0
- package/src/intent/create-intent.service.ts +129 -0
- package/src/intent/feasable-intent.service.ts +80 -0
- package/src/intent/fulfill-intent.service.ts +318 -0
- package/src/intent/intent.controller.ts +199 -0
- package/src/intent/intent.module.ts +49 -0
- package/src/intent/schemas/intent-call-data.schema.ts +16 -0
- package/src/intent/schemas/intent-data.schema.ts +114 -0
- package/src/intent/schemas/intent-source.schema.ts +33 -0
- package/src/intent/schemas/intent-token-amount.schema.ts +14 -0
- package/src/intent/schemas/reward-data.schema.ts +48 -0
- package/src/intent/schemas/route-data.schema.ts +52 -0
- package/src/intent/schemas/watch-event.schema.ts +32 -0
- package/src/intent/tests/create-intent.service.spec.ts +215 -0
- package/src/intent/tests/feasable-intent.service.spec.ts +155 -0
- package/src/intent/tests/fulfill-intent.service.spec.ts +564 -0
- package/src/intent/tests/utils-intent.service.spec.ts +308 -0
- package/src/intent/tests/utils.spec.ts +62 -0
- package/src/intent/tests/validate-intent.service.spec.ts +297 -0
- package/src/intent/tests/validation.service.spec.ts +337 -0
- package/src/intent/utils-intent.service.ts +168 -0
- package/src/intent/utils.ts +37 -0
- package/src/intent/validate-intent.service.ts +176 -0
- package/src/intent/validation.sevice.ts +223 -0
- package/src/interceptors/big-int.interceptor.ts +30 -0
- package/src/intervals/interval.module.ts +18 -0
- package/src/intervals/retry-infeasable-intents.service.ts +89 -0
- package/src/intervals/tests/retry-infeasable-intents.service.spec.ts +167 -0
- package/src/kms/errors.ts +0 -0
- package/src/kms/kms.module.ts +12 -0
- package/src/kms/kms.service.ts +65 -0
- package/src/kms/tests/kms.service.spec.ts +60 -0
- package/src/liquidity-manager/jobs/check-balances-cron.job.ts +229 -0
- package/src/liquidity-manager/jobs/liquidity-manager.job.ts +52 -0
- package/src/liquidity-manager/jobs/rebalance.job.ts +61 -0
- package/src/liquidity-manager/liquidity-manager.module.ts +29 -0
- package/src/liquidity-manager/processors/base.processor.ts +117 -0
- package/src/liquidity-manager/processors/eco-protocol-intents.processor.ts +34 -0
- package/src/liquidity-manager/processors/grouped-jobs.processor.ts +103 -0
- package/src/liquidity-manager/queues/liquidity-manager.queue.ts +48 -0
- package/src/liquidity-manager/schemas/rebalance-token.schema.ts +32 -0
- package/src/liquidity-manager/schemas/rebalance.schema.ts +32 -0
- package/src/liquidity-manager/services/liquidity-manager.service.ts +188 -0
- package/src/liquidity-manager/services/liquidity-provider.service.ts +25 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service.spec.ts +125 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service.ts +117 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/utils/get-transaction-hashes.ts +16 -0
- package/src/liquidity-manager/tests/liquidity-manager.service.spec.ts +142 -0
- package/src/liquidity-manager/types/token-state.enum.ts +5 -0
- package/src/liquidity-manager/types/types.d.ts +52 -0
- package/src/liquidity-manager/utils/address.ts +5 -0
- package/src/liquidity-manager/utils/math.ts +9 -0
- package/src/liquidity-manager/utils/serialize.spec.ts +24 -0
- package/src/liquidity-manager/utils/serialize.ts +47 -0
- package/src/liquidity-manager/utils/token.ts +91 -0
- package/src/main.ts +63 -0
- package/src/nest-redlock/nest-redlock.config.ts +14 -0
- package/src/nest-redlock/nest-redlock.interface.ts +5 -0
- package/src/nest-redlock/nest-redlock.module.ts +64 -0
- package/src/nest-redlock/nest-redlock.service.ts +59 -0
- package/src/prover/proof.service.ts +184 -0
- package/src/prover/prover.module.ts +10 -0
- package/src/prover/tests/proof.service.spec.ts +154 -0
- package/src/quote/dto/quote.intent.data.dto.ts +35 -0
- package/src/quote/dto/quote.reward.data.dto.ts +67 -0
- package/src/quote/dto/quote.route.data.dto.ts +71 -0
- package/src/quote/dto/types.ts +18 -0
- package/src/quote/errors.ts +215 -0
- package/src/quote/quote.module.ts +17 -0
- package/src/quote/quote.service.ts +299 -0
- package/src/quote/schemas/quote-call.schema.ts +16 -0
- package/src/quote/schemas/quote-intent.schema.ts +27 -0
- package/src/quote/schemas/quote-reward.schema.ts +24 -0
- package/src/quote/schemas/quote-route.schema.ts +30 -0
- package/src/quote/schemas/quote-token.schema.ts +14 -0
- package/src/quote/tests/quote.service.spec.ts +444 -0
- package/src/sign/atomic-signer.service.ts +24 -0
- package/src/sign/atomic.nonce.service.ts +114 -0
- package/src/sign/kms-account/kmsToAccount.ts +73 -0
- package/src/sign/kms-account/signKms.ts +30 -0
- package/src/sign/kms-account/signKmsTransaction.ts +37 -0
- package/src/sign/kms-account/signKmsTypedData.ts +21 -0
- package/src/sign/nonce.service.ts +89 -0
- package/src/sign/schemas/nonce.schema.ts +36 -0
- package/src/sign/sign.controller.ts +52 -0
- package/src/sign/sign.helper.ts +23 -0
- package/src/sign/sign.module.ts +27 -0
- package/src/sign/signer-kms.service.ts +27 -0
- package/src/sign/signer.service.ts +26 -0
- package/src/solver/filters/tests/valid-smart-wallet.service.spec.ts +87 -0
- package/src/solver/filters/valid-smart-wallet.service.ts +58 -0
- package/src/solver/solver.module.ts +10 -0
- package/src/transaction/multichain-public-client.service.ts +15 -0
- package/src/transaction/smart-wallets/kernel/actions/encodeData.kernel.ts +57 -0
- package/src/transaction/smart-wallets/kernel/create-kernel-client-v2.account.ts +183 -0
- package/src/transaction/smart-wallets/kernel/create.kernel.account.ts +270 -0
- package/src/transaction/smart-wallets/kernel/index.ts +2 -0
- package/src/transaction/smart-wallets/kernel/kernel-account-client-v2.service.ts +90 -0
- package/src/transaction/smart-wallets/kernel/kernel-account-client.service.ts +107 -0
- package/src/transaction/smart-wallets/kernel/kernel-account.client.ts +105 -0
- package/src/transaction/smart-wallets/kernel/kernel-account.config.ts +34 -0
- package/src/transaction/smart-wallets/simple-account/create.simple.account.ts +19 -0
- package/src/transaction/smart-wallets/simple-account/index.ts +2 -0
- package/src/transaction/smart-wallets/simple-account/simple-account-client.service.ts +42 -0
- package/src/transaction/smart-wallets/simple-account/simple-account.client.ts +83 -0
- package/src/transaction/smart-wallets/simple-account/simple-account.config.ts +5 -0
- package/src/transaction/smart-wallets/smart-wallet.types.ts +38 -0
- package/src/transaction/smart-wallets/utils.ts +14 -0
- package/src/transaction/transaction.module.ts +25 -0
- package/src/transaction/viem_multichain_client.service.ts +100 -0
- package/src/transforms/viem-address.decorator.ts +14 -0
- package/src/utils/bigint.ts +44 -0
- package/src/utils/types.ts +18 -0
- package/src/watch/intent/tests/watch-create-intent.service.spec.ts +257 -0
- package/src/watch/intent/tests/watch-fulfillment.service.spec.ts +141 -0
- package/src/watch/intent/watch-create-intent.service.ts +106 -0
- package/src/watch/intent/watch-event.service.ts +133 -0
- package/src/watch/intent/watch-fulfillment.service.ts +115 -0
- package/src/watch/watch.module.ts +13 -0
- package/test/app.e2e-spec.ts +21 -0
- package/test/jest-e2e.json +9 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +29 -0
@@ -0,0 +1,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,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,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
|
+
}
|