Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/upper limit0107 #286

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3fd4ca7
refactor: Import local packages from npm
wenty22 Dec 23, 2024
bc1fdc7
Merge branch 'feat/tokenApi1216' into wenty/aggregator
wenty22 Dec 23, 2024
326309a
refactor: Adjust config structure
wenty22 Dec 24, 2024
7c02d98
Merge branch 'main' into wenty/aggregator
wenty22 Jan 2, 2025
ea1d1c4
feat: Support multiple to tokens
wenty22 Jan 2, 2025
d36a484
feat: Support multiple to tokens
wenty22 Jan 3, 2025
9cd2d03
Merge branch 'main' into wenty/aggregator
wenty22 Jan 3, 2025
ed8e2e6
feat: Support multiple to tokens
wenty22 Jan 6, 2025
e895128
feat: Support multiple to tokens
wenty22 Jan 6, 2025
54699e4
feat: Filter no price tokens
wenty22 Jan 6, 2025
82eac74
feat: Move config to api server
wenty22 Jan 6, 2025
92b12a9
feat: Update syncBridgeInfo task cronTime
wenty22 Jan 6, 2025
d6755da
Merge branch 'main' into wenty/aggregator
wenty22 Jan 8, 2025
46d80be
feat: Change deBridgeReferralCode to an environment variable
wenty22 Jan 8, 2025
f36573e
feat: Add cache to filtered data
wenty22 Jan 8, 2025
b9b05ce
Merge branch 'main' into wenty/aggregator
wenty22 Jan 8, 2025
6c5e1ab
style: Format code styles
wenty22 Jan 8, 2025
db7bf0b
feat: Add app version
wenty22 Jan 8, 2025
322b18c
feat: Update confirmation popup amount styling
Halibao-Lala Jan 9, 2025
d5065a6
chore: Release version
Halibao-Lala Jan 9, 2025
0043ef1
fix: Fix merge conflicts
Halibao-Lala Jan 9, 2025
93b0b2f
feat: Update eth & weth mapping rule
wenty22 Jan 9, 2025
24282ef
fix: Fix one-to-many logic of special tokens do not take effect
wenty22 Jan 9, 2025
faddfa8
feat: Input upper limit checking
Halibao-Lala Jan 9, 2025
7cf5547
fix: Fix stargate mapping issue
wenty22 Jan 10, 2025
9e284a1
fix: Hide receive info before select a toToken
wenty22 Jan 10, 2025
5e97e6c
Merge branch 'wenty/aggregator' into feat/upperLimit0107
Halibao-Lala Jan 10, 2025
5df66de
feat: Check token price before sending transaction
Halibao-Lala Jan 10, 2025
660e448
feat: Fee loading timeout model
Halibao-Lala Jan 14, 2025
273db6f
feat: Stargate max decimals error message
Halibao-Lala Jan 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
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
5 changes: 5 additions & 0 deletions .release/.changeset/blue-goats-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@bnb-chain/canonical-bridge-widget": patch
---

chore: Update confirmation popup amount styling
11 changes: 11 additions & 0 deletions .release/.changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"mode": "pre",
"tag": "alpha",
"initialVersions": {
"@bnb-chain/canonical-bridge-sdk": "0.4.7",
"@bnb-chain/canonical-bridge-widget": "0.5.18"
},
"changesets": [
"blue-goats-shave"
]
}
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,44 @@ 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
Loading