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