Skip to content

Commit

Permalink
Merge pull request #274 from bnb-chain/wenty/aggregator
Browse files Browse the repository at this point in the history
feat: Add cahe to filtered config
  • Loading branch information
wenty22 authored Jan 8, 2025
2 parents c87f8b0 + b9b05ce commit 5e4d812
Show file tree
Hide file tree
Showing 635 changed files with 8,369 additions and 28,556 deletions.
1 change: 1 addition & 0 deletions .github/workflows/example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
NEXT_PUBLIC_ASSET_PREFIX=$ASSET_PREFIX
NEXT_PUBLIC_SERVER_ENDPOINT=$SERVER_ENDPOINT
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=$WALLET_CONNECT_PROJECT_ID
NEXT_PUBLIC_DEBRIDGE_REFERRAL_CODE=$DEBRIDGE_REFERRAL_CODE
EOF
env:
APP_NAME: canonical-bridge
Expand Down
11 changes: 6 additions & 5 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/node_modules": true,
"**/.next": true,
// "**/node_modules": true,
// "**/.next": true,
"**/*.log": true,
"**/dist": true,
"**/.rush": true,
"**/temp": true,
// "**/dist": true,
// "**/.rush": true,
// "**/temp": true,
"**/tsconfig.tsbuildinfo": true
},
"[typescript]": {
Expand Down Expand Up @@ -48,6 +48,7 @@
"Blocto",
"bnbchain",
"cbridge",
"Chakra",
"debridge",
"LAMPORTS",
"multichain",
Expand Down
2 changes: 1 addition & 1 deletion apps/canonical-bridge-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"rxjs": "^7.8.1"
},
"devDependencies": {
"@bnb-chain/prettier-config": "workspace:*",
"@bnb-chain/prettier-config": "^1",
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@types/express": "^4.17.17",
Expand Down
3 changes: 1 addition & 2 deletions apps/canonical-bridge-server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { AllExceptionFilter } from './common/filters/all-exception.filter';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
import { TransformInterceptor } from './common/interceptors/transform.interceptor';
import { TimeoutInterceptor } from './common/interceptors/timeout.interceptor';
import { REDIS_HOST, REDIS_PORT, TIME } from './common/constants';
import { REDIS_HOST, REDIS_PORT } from './common/constants';
import { TokenModule } from './module/token/token.module';
import { BullModule } from '@nestjs/bullmq';
import { Web3Module } from '@/shared/web3/web3.module';
Expand All @@ -32,7 +32,6 @@ import { BridgeModule } from '@/module/bridge/bridge.module';
HealthModule,
ScheduleModule.forRoot(),
CacheModule.register<RedisOptions>({
ttl: TIME.DAY,
isGlobal: true,
store: () => redisStore({ host: REDIS_HOST, port: REDIS_PORT }),
}),
Expand Down
10 changes: 10 additions & 0 deletions apps/canonical-bridge-server/src/common/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export enum Tasks {
fetchMeson = 'fetchMeson',
cacheCmcConfig = 'cacheCmcConfig',
cacheLlamaConfig = 'cacheLlamaConfig',

filterCBridge = 'filterCBridge',
filterDeBridge = 'filterDeBridge',
filterStargate = 'filterStargate',
filterMeson = 'filterMeson',
}

export const TOKEN_REQUEST_LIMIT = 1000;
Expand All @@ -53,6 +58,11 @@ export const CACHE_KEY = {
CMC_CONFIG: 'cmc:config',
LLAMA_CONFIG: 'llama:config',
PLATFORM_MAPPING: 'llama:platform',

FIELDED_CBRIDGE_CONFIG: 'bridge:filtered:cbridge',
FIELDED_DEBRIDGE_CONFIG: 'bridge:filtered:debridge',
FIELDED_STARGATE_CONFIG: 'bridge:filtered:stargate',
FIELDED_MESON_CONFIG: 'bridge:filtered:meson',
};

export const JOB_KEY = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,36 @@ export class BridgeController {
getMesonConfig() {
return this.cache.get(CACHE_KEY.MESON_CONFIG);
}

@Get('/v2/cbridge')
async getCbridgeConfigV2() {
const config = await this.cache.get(CACHE_KEY.FIELDED_CBRIDGE_CONFIG);
if (config) return config;

return this.cache.get(CACHE_KEY.CBRIDGE_CONFIG);
}

@Get('/v2/debridge')
async getDeBridgeConfigV2() {
const config = await this.cache.get(CACHE_KEY.FIELDED_DEBRIDGE_CONFIG);
if (config) return config;

return this.cache.get(CACHE_KEY.DEBRIDGE_CONFIG);
}

@Get('/v2/stargate')
async getStargateConfigV2() {
const config = await this.cache.get(CACHE_KEY.FIELDED_STARGATE_CONFIG);
if (config) return config;

return this.cache.get(CACHE_KEY.STARGATE_CONFIG);
}

@Get('/v2/meson')
async getMesonConfigV2() {
const config = await this.cache.get(CACHE_KEY.FIELDED_MESON_CONFIG);
if (config) return config;

return this.cache.get(CACHE_KEY.MESON_CONFIG);
}
}
231 changes: 230 additions & 1 deletion apps/canonical-bridge-server/src/module/bridge/bridge.processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ import { Inject, Logger } from '@nestjs/common';
import { Job } from 'bullmq';
import { Web3Service } from '@/shared/web3/web3.service';
import { Cache, CACHE_MANAGER } from '@nestjs/cache-manager';
import { IDebridgeToken } from '@/shared/web3/web3.interface';
import {
IDebridgeConfig,
IDebridgeToken,
IMesonChain,
IStargateBridgeTokenInfo,
ITransferConfigsForAll,
ITransferToken,
} from '@/shared/web3/web3.interface';
import { ITokenPriceRecord } from '@/module/token/token.interface';
import { isEmpty } from 'lodash';

@Processor(Queues.SyncBridge)
export class BridgeProcessor extends WorkerHost {
Expand All @@ -27,6 +36,15 @@ export class BridgeProcessor extends WorkerHost {
return this.fetchMeson();
case Tasks.fetchStargate:
return this.fetchStargate();

case Tasks.filterCBridge:
return this.filterCBridge();
case Tasks.filterDeBridge:
return this.filterDeBridge();
case Tasks.filterStargate:
return this.filterStargate();
case Tasks.filterMeson:
return this.filterMeson();
default:
}
}
Expand Down Expand Up @@ -65,4 +83,215 @@ export class BridgeProcessor extends WorkerHost {
if (!config) return;
await this.cache.set(`${CACHE_KEY.MESON_CONFIG}`, config, TIME.DAY);
}

private updateDeBridgeConfigManually(config?: IDebridgeConfig) {
if (!config) return config;

const finalConfig = {
tokens: [],
...config,
};

const extraConfigs: Record<number, any[]> = {
1: [
{
action: 'replace',
target: '0xebd9d99a3982d547c5bb4db7e3b1f9f14b67eb83',
data: {
address: '0x2dfF88A56767223A5529eA5960Da7A3F5f766406',
symbol: 'ID',
decimals: 18,
name: 'SPACE ID',
logoURI: '',
eip2612: false,
tags: ['tokens'],
},
},
{
action: 'append',
data: {
address: '0x152649eA73beAb28c5b49B26eb48f7EAD6d4c898',
symbol: 'Cake',
decimals: 18,
name: 'PancakeSwap Token',
logoURI: '',
eip2612: false,
tags: ['tokens'],
},
},
],
};

Object.entries(finalConfig.tokens).forEach(([key, value]) => {
const chainId = Number(key);
const extraConfig = extraConfigs[chainId];

if (extraConfig) {
extraConfig.forEach((item) => {
const { action, target, data } = item;
if (!value[data.address]) {
if (action === 'replace') {
const index = value.findIndex((item) => item.address === target);
if (index > -1) {
value[index] = data;
}
} else if (action === 'append') {
(value as any).push(data);
}
}
});
}
});

return finalConfig;
}

public async getPriceConfig() {
const [cmcRes, llamaRes] = await Promise.allSettled([
this.cache.get<ITokenPriceRecord>(CACHE_KEY.CMC_CONFIG),
this.cache.get<ITokenPriceRecord>(CACHE_KEY.LLAMA_CONFIG),
]);
return {
cmc: cmcRes.status === 'fulfilled' ? cmcRes.value : {},
llama: llamaRes.status === 'fulfilled' ? llamaRes.value : {},
};
}

public hasTokenPrice(params: {
prices: { cmc?: ITokenPriceRecord; llama?: ITokenPriceRecord };
tokenSymbol: string;
tokenAddress: string;
}) {
if (isEmpty(params.prices.cmc) && isEmpty(params.prices.llama)) {
return true;
}
const key1 = `${params.tokenSymbol?.toLowerCase()}:${params.tokenAddress?.toLowerCase()}`;
const key3 = params.tokenSymbol?.toLowerCase();
const key2 = `ethereum:${key3}`;

const price =
params.prices.cmc?.[key1]?.price ??
params.prices.llama?.[key1]?.price ??
params.prices.cmc?.[key2]?.price ??
params.prices.llama?.[key2]?.price ??
params.prices.cmc?.[key3]?.price ??
params.prices.llama?.[key3]?.price;

return !!price;
}

async filterCBridge() {
const config = await this.cache.get<ITransferConfigsForAll>(CACHE_KEY.CBRIDGE_CONFIG);
if (!config) return;

const prices = await this.getPriceConfig();

const chainToken: Record<number, { token: ITransferToken[] }> = {};
Object.entries(config.chain_token).forEach(([key, { token }]) => {
const chainId = Number(key);
chainToken[chainId] = { token: [] };
chainToken[chainId].token = token.filter((e) => {
return this.hasTokenPrice({
prices,
tokenAddress: e.token.address,
tokenSymbol: e.token.symbol,
});
});
});

const peggedPairConfigs: ITransferConfigsForAll['pegged_pair_configs'] =
config.pegged_pair_configs.filter((e) => {
const orgHasPrice = this.hasTokenPrice({
prices,
tokenSymbol: e.org_token.token.symbol,
tokenAddress: e.org_token.token.address,
});

const peggedHasPrice = this.hasTokenPrice({
prices,
tokenSymbol: e.pegged_token.token.symbol,
tokenAddress: e.pegged_token.token.address,
});

return orgHasPrice && peggedHasPrice;
});

const finalConfig: ITransferConfigsForAll = {
...config,
chain_token: chainToken,
pegged_pair_configs: peggedPairConfigs,
};

await this.cache.set(`${CACHE_KEY.FIELDED_CBRIDGE_CONFIG}`, finalConfig, TIME.DAY);
}

async filterDeBridge() {
const _config = await this.cache.get<IDebridgeConfig>(CACHE_KEY.DEBRIDGE_CONFIG);
const config = this.updateDeBridgeConfigManually(_config);
if (!config) return config;

const prices = await this.getPriceConfig();
const chainTokens: Record<number, IDebridgeToken[]> = {};

Object.entries(config.tokens).forEach(([key, tokens]) => {
const chainId = Number(key);
chainTokens[chainId] = tokens.filter((e) => {
return this.hasTokenPrice({
prices,
tokenAddress: e.address,
tokenSymbol: e.symbol,
});
});
});

const finalConfig: IDebridgeConfig = {
...config,
tokens: chainTokens,
};

await this.cache.set(`${CACHE_KEY.FIELDED_DEBRIDGE_CONFIG}`, finalConfig, TIME.DAY);
}

async filterStargate() {
const config = await this.cache.get<IStargateBridgeTokenInfo[]>(CACHE_KEY.STARGATE_CONFIG);
if (!config) return config;

const prices = await this.getPriceConfig();

const finalConfig = config.filter((e) => {
return this.hasTokenPrice({
prices,
tokenAddress: e.token.address,
tokenSymbol: e.token.symbol,
});
});

await this.cache.set(`${CACHE_KEY.FIELDED_STARGATE_CONFIG}`, finalConfig, TIME.DAY);
}

async filterMeson() {
const config = await this.cache.get<IMesonChain[]>(CACHE_KEY.MESON_CONFIG);
if (!config) return config;

const prices = await this.getPriceConfig();

const finalConfig: IMesonChain[] = [];
config.forEach((chain) => {
const tokens = chain.tokens.filter((e) => {
return this.hasTokenPrice({
prices,
tokenAddress: e.addr,
tokenSymbol: e.symbol,
});
});
if (tokens?.length) {
finalConfig.push({
...chain,
tokens,
});
}
});

await this.cache.set(`${CACHE_KEY.FIELDED_MESON_CONFIG}`, finalConfig, TIME.DAY);
}
}
Loading

0 comments on commit 5e4d812

Please sign in to comment.