Skip to content

Commit

Permalink
Liquidity Manager (#66)
Browse files Browse the repository at this point in the history
* liquidity manager file structure

* rebalancing logic

* solve lint warnings

* increase liquidity manager processor concurrency

* liquidity provider structure

* LiFi implementation

* fix jest module name mapper

* increase check balances cron job interval

* fix unit tests

* update eco routes package

* update beta eco routes version

* fix optional prover

* only accept patch updates automatically for eco routes

* upgrading to eco routes-ts ^0.1.10-beta
refactoring code and mongo record for new AUDIT protocol

* change warning logs to debug logs

* fix table formatting

* move bigint conversion (#68)

* Batch fulfill (#71)

* move bigint conversion

* updating repo in package.json (#70)

* updating repo in package.json

* linter

* adding fulfillHyperBatched to fulfillment based on aws configs

* linter

* changing to run as name

* Proof time change (#73)

* move bigint conversion

* updating times for proofs

* remove console

* @eco-foundation/routes beta

* use job schedulers

* move liquidity manager parameters to config

* avoid returning undefined

* rename LiquidityProviderService

* move job interval to config

* refactor job manager class

* reuse errors

* jest test init

* Disable storage prover (#74)

* move bigint conversion

* disabling storage prover from being accepted by solver

* update @eco-foundation/routes-ts version

* upgrade LiFi SDK version

* LiFiProviderService service unit tests

* Same chain bug (#78)

* move bigint conversion

* disabling storage prover from being accepted by solver

* add sameChainFulfill check to validate intent

* Add check to unsubscribe (#75)

* move bigint conversion

* disabling storage prover from being accepted by solver

* updating routes-ts to ~0.2.10-beta update only on patch

* Ed 4570 retry unfeasable (#76)

* move bigint conversion

* moving watch services into own module. adding watch fulfill intent service

* creating watch fulfillment event

* refactoring watch create intent to use same abstract parent

* adding tests for watch fulfillment
adding inbox processor
adding intent utils method for update - > needs more work and tests

* adding default intervals, intentconfigs, and liquiditymanager to config defaults.ts
removing eventemitter from app modules
adding interval modeule and service
adding interval processor and queue
adding retry_intent to source intent queue

* adding skeleton of retry infeasable

* disabling storage prover from being accepted by solver

* updating routes-ts to ~0.2.10-beta update only on patch

* fixing merge

* adding retry infeasable intents tests

* Api (#77)

* adding balance api endpoint
adding cache manager to project

* adding cache configs to configs and defaults

* linter

* clean up

---------

Co-authored-by: Stoyan Dimitrov <s.dimitrov19@gmail.com>
  • Loading branch information
carlosfebres and StoyanD authored Jan 8, 2025
1 parent 4391517 commit 907d236
Show file tree
Hide file tree
Showing 85 changed files with 5,056 additions and 5,502 deletions.
47 changes: 47 additions & 0 deletions config/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export default {
secretID: 'eco-solver-configs-dev',
},
],
cache: {
ttl: 10_000, // milliseconds till cache key expires
},
redis: {
options: {
single: {
Expand Down Expand Up @@ -45,6 +48,50 @@ export default {
},
},
},
intervals: {
retryInfeasableIntents: {
repeatOpts: {
every: 10000,
},
jobTemplate: {
name: 'retry-infeasable-intents',
data: {},
},
},
defaults: {
repeatOpts: {
every: 10000,
},
jobTemplate: {
name: 'default-interval-job',
data: {},
opts: {
removeOnComplete: true,
removeOnFail: true,

attempts: 3,
backoff: {
type: 'exponential',
delay: 2_000,
},
},
},
},
},
intentConfigs: {
proofs: {
storage_duration_seconds: 604800,
hyperlane_duration_seconds: 3600,
},
},
liquidityManager: {
intervalDuration: 300000,
targetSlippage: 0.02,
thresholds: {
surplus: 0.1,
deficit: 0.2,
},
},
externalAPIs: {},
logger: {
usePino: true,
Expand Down
3 changes: 3 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ module.exports = {
collectCoverageFrom: ['**/*.(t|j)s'],
coverageDirectory: '../coverage',
testEnvironment: 'node',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>//$1',
},
}
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@
},
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.592.0",
"@eco-foundation/routes": "^0.0.508-beta",
"@eco-foundation/routes-ts": "~0.2.10-beta",
"@launchdarkly/node-server-sdk": "^9.7.1",
"@liaoliaots/nestjs-redis-health": "^9.0.4",
"@lifi/sdk": "^3.5.0",
"@nestjs/bullmq": "^10.1.1",
"@nestjs/cache-manager": "3.0.0-next.0",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.2",
"@nestjs/core": "^10.0.0",
Expand All @@ -54,6 +56,7 @@
"@nestjs/terminus": "^10.2.3",
"alchemy-sdk": "^3.3.1",
"bullmq": "^5.8.5",
"cache-manager": "^6.3.2",
"config": "^3.3.11",
"date-fns": "^3.6.0",
"lodash": "^4.17.21",
Expand All @@ -64,7 +67,8 @@
"redlock": "^5.0.0-beta.2",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"viem": "^2.21.32"
"table": "^6.8.2",
"viem": "^2.22.4"
},
"devDependencies": {
"@golevelup/ts-jest": "^0.5.0",
Expand Down
24 changes: 24 additions & 0 deletions src/api/api.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { BalanceController } from '@/api/balance.controller'
import { BalanceModule } from '@/balance/balance.module'
import { EcoConfigService } from '@/eco-configs/eco-config.service'
import { CacheInterceptor, CacheModule } from '@nestjs/cache-manager'
import { Module } from '@nestjs/common'
import { APP_INTERCEPTOR } from '@nestjs/core'

@Module({
imports: [
BalanceModule,
CacheModule.registerAsync({
useFactory: async (configService: EcoConfigService) => configService.getCache(),
inject: [EcoConfigService],
}),
],
controllers: [BalanceController],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: CacheInterceptor,
},
],
})
export class ApiModule {}
16 changes: 16 additions & 0 deletions src/api/balance.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { BalanceService } from '@/balance/balance.service'
import { API_ROOT, BALANCE_ROUTE } from '@/common/routes/constants'
import { convertBigIntsToStrings } from '@/common/viem/utils'
import { CacheInterceptor } from '@nestjs/cache-manager'
import { Controller, Get, UseInterceptors } from '@nestjs/common'

@Controller(API_ROOT + BALANCE_ROUTE)
@UseInterceptors(CacheInterceptor)
export class BalanceController {
constructor(private readonly balanceService: BalanceService) {}

@Get()
async getBalances() {
return convertBigIntsToStrings(await this.balanceService.getAllTokenData())
}
}
53 changes: 53 additions & 0 deletions src/api/tests/balance.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Test, TestingModule } from '@nestjs/testing'
import { BalanceController } from '../balance.controller'
import { BalanceService } from '@/balance/balance.service'
import { CACHE_MANAGER } from '@nestjs/cache-manager'
import { createMock } from '@golevelup/ts-jest'

describe('BalanceController Test', () => {
let balanceController: BalanceController
let balanceService: BalanceService

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [BalanceController],
providers: [
{
provide: BalanceService,
useValue: createMock<BalanceService>(),
},
{
provide: CACHE_MANAGER,
useValue: {
get: jest.fn(),
set: jest.fn(),
},
},
],
}).compile()

balanceController = module.get<BalanceController>(BalanceController)
balanceService = module.get<BalanceService>(BalanceService)
})

it('should be defined', () => {
expect(balanceController).toBeDefined()
})

describe('getBalances', () => {
it('should return an array of balances', async () => {
const result = []
jest.spyOn(balanceService, 'getAllTokenData').mockResolvedValue(result)

expect(await balanceController.getBalances()).toEqual(result)
})

it('should call balanceService.getAllTokenData', async () => {
const getAllTokenDataSpy = jest.spyOn(balanceService, 'getAllTokenData').mockResolvedValue([])

await balanceController.getBalances()

expect(getAllTokenDataSpy).toHaveBeenCalled()
})
})
})
14 changes: 9 additions & 5 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { ChainMonitorModule } from './chain-monitor/chain-monitor.module'
import { EcoConfigService } from './eco-configs/eco-config.service'
import { LoggerModule } from 'nestjs-pino'
import { MongooseModule } from '@nestjs/mongoose'
import { EventEmitterModule } from '@nestjs/event-emitter'
import { IntentModule } from './intent/intent.module'
import { IntentSourceModel } from './intent/schemas/intent-source.schema'
import { BalanceModule } from './balance/balance.module'
Expand All @@ -14,21 +13,24 @@ import { HealthModule } from './health/health.module'
import { ProcessorModule } from './bullmq/processors/processor.module'
import { SolverModule } from './solver/solver.module'
import { FlagsModule } from './flags/flags.module'
import { LiquidityManagerModule } from '@/liquidity-manager/liquidity-manager.module'
import { ApiModule } from '@/api/api.module'
import { WatchModule } from '@/watch/watch.module'
import { IntervalModule } from '@/intervals/interval.module'

@Module({
imports: [
ApiModule,
BalanceModule,
ChainMonitorModule,
EcoConfigModule.withAWS(),
EventEmitterModule.forRoot({
// the delimiter used to segment namespaces
delimiter: '.',
}),

FlagsModule,
HealthModule,
IntentModule,
SignModule,
IntentSourceModel,
IntervalModule,
ProcessorModule,
MongooseModule.forRootAsync({
inject: [EcoConfigService],
Expand All @@ -41,6 +43,8 @@ import { FlagsModule } from './flags/flags.module'
}),
ProverModule,
SolverModule,
LiquidityManagerModule,
WatchModule,
...getPino(),
],
controllers: [],
Expand Down
Loading

0 comments on commit 907d236

Please sign in to comment.