Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8f96dac
add first draft
gianfra-t Jan 15, 2026
16885b4
move dynamic token config to shared, adjust checks and getters
gianfra-t Jan 15, 2026
9edce1e
test react window
gianfra-t Jan 16, 2026
e75470c
solve cyclic import issue
gianfra-t Jan 19, 2026
d0d9564
use balances from alchemy endpoint
gianfra-t Jan 19, 2026
c30b3de
Merge branch 'dynamic-onchain-tokens' of github.com:pendulum-chain/vo…
gianfra-t Jan 19, 2026
8c0d7f3
fetch balances from portfolio endpoint
gianfra-t Jan 19, 2026
02dda7c
order balance by usd value
gianfra-t Jan 19, 2026
2eeded6
replace react-window with react-virtual
gianfra-t Jan 19, 2026
b1b5d5b
improve list ordering, performance
gianfra-t Jan 19, 2026
0ba8c1c
add proper logo to Onramp selected token
gianfra-t Jan 19, 2026
42960cf
re-arrange import
gianfra-t Jan 20, 2026
40dd15a
remove unused coins imgs
Sharqiewicz Jan 21, 2026
13ca8a7
implement TokenIconWithNetwork
Sharqiewicz Jan 21, 2026
41a8c11
fix lint issues
Sharqiewicz Jan 21, 2026
a2eaa7d
refactor getting asset icons
Sharqiewicz Jan 21, 2026
0c43f6b
refactor PopularTokens tokens definition
Sharqiewicz Jan 21, 2026
33a0b90
remove unused tokens from useGetAssetIcon
Sharqiewicz Jan 21, 2026
f7febd3
refactor tanstack virtualizer definition
Sharqiewicz Jan 21, 2026
9f98bf0
optimize sorting tokens by balance
Sharqiewicz Jan 21, 2026
c5b5bdc
fix: normalize token keys to uppercase to prevent duplicates
Sharqiewicz Jan 28, 2026
eeb5d24
feat: add fallbackLogoURI property to EVM tokens
Sharqiewicz Jan 28, 2026
71e0c5a
feat: implement fallback image handling in token selection
Sharqiewicz Jan 28, 2026
e1606f1
feat: implement fallback image handling in ramp inputs
Sharqiewicz Jan 28, 2026
0f25c6a
feat: implement fallback image handling in transaction summary
Sharqiewicz Jan 28, 2026
8075f76
Add loading placeholder for token images
Sharqiewicz Jan 28, 2026
e28930a
feat: add TokenImage component with loading and fallback support
Sharqiewicz Jan 28, 2026
2c07cb0
feat: add getTokenLogoURIs helper function
Sharqiewicz Jan 28, 2026
98f5d33
refactor: use TokenImage component for token icons
Sharqiewicz Jan 28, 2026
1cf91f7
fix type issues
Sharqiewicz Jan 28, 2026
c5f9581
change hex colors to oklch
Sharqiewicz Jan 28, 2026
471088c
fix token filtering to only our present chains
Sharqiewicz Jan 28, 2026
5cfae2b
change isOnChainToken type guard
Sharqiewicz Jan 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { generateApiKey, getKeyPrefix, hashApiKey } from "../../middlewares/apiK
*/
export async function createApiKey(req: Request, res: Response): Promise<void> {
try {
const { partnerName } = req.params;
const partnerName = req.params.partnerName as string;
const { name, expiresAt } = req.body;

// Verify at least one partner with this name exists and is active
Expand Down Expand Up @@ -112,7 +112,7 @@ export async function createApiKey(req: Request, res: Response): Promise<void> {
*/
export async function listApiKeys(req: Request, res: Response): Promise<void> {
try {
const { partnerName } = req.params;
const partnerName = req.params.partnerName as string;

// Verify partner exists
const partners = await Partner.findAll({
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/api/controllers/maintenance.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const getAllMaintenanceSchedules: RequestHandler = async (_, res) => {
*/
export const updateScheduleActiveStatus: RequestHandler = async (req, res) => {
try {
const { id } = req.params;
const id = req.params.id as string;
const { isActive } = req.body;

if (typeof isActive !== "boolean") {
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/api/controllers/metrics.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const zeroVolume = (key: string, keyName: "day" | "month"): any => ({
});

async function getMonthlyVolumes(): Promise<MonthlyVolume[]> {
const cacheKey = `monthly`;
const cacheKey = "monthly";
const cached = cache.get<MonthlyVolume[]>(cacheKey);
if (cached) return cached;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class DistributeFeesHandler extends BasePhaseHandler {
logger.info(`Found existing distribute fee hash for ramp ${state.id}: ${existingHash}`);

const status = await this.checkExtrinsicStatus(existingHash).catch((_: unknown) => {
throw this.createRecoverableError(`Failed to check extrinsic status`);
throw this.createRecoverableError("Failed to check extrinsic status");
});

if (status === ExtrinsicStatus.Success) {
Expand Down
25 changes: 23 additions & 2 deletions apps/api/src/api/services/priceFeed.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
EvmToken,
getPendulumDetails,
getTokenOutAmount,
getTokenUsdPrice,
isFiatToken,
normalizeTokenSymbol,
PENDULUM_USDC_AXL,
Expand Down Expand Up @@ -488,6 +489,16 @@ export class PriceFeedService {
}

private async convertUsdToCrypto(amount: string, toCurrency: RampCurrency, decimals: number): Promise<string> {
// Try dynamic token price first
const dynamicPrice = getTokenUsdPrice(toCurrency);
if (dynamicPrice !== undefined && dynamicPrice > 0) {
const result = new Big(amount).div(dynamicPrice).toFixed(decimals);
logger.debug(`Converted ${amount} USD to ${result} ${toCurrency} using dynamic price: ${dynamicPrice}`);
return result;
}

// Fall back to CoinGecko
logger.debug(`No dynamic price for ${toCurrency}, falling back to CoinGecko`);
const tokenId = this.getCoinGeckoTokenId(toCurrency);
if (!tokenId) {
throw new Error(`No CoinGecko token ID mapping for ${toCurrency}`);
Expand All @@ -499,19 +510,29 @@ export class PriceFeedService {
}

const result = new Big(amount).div(cryptoPriceUSD).toFixed(decimals);
logger.debug(`Converted ${amount} USD to ${result} ${toCurrency} using price: ${cryptoPriceUSD}`);
logger.debug(`Converted ${amount} USD to ${result} ${toCurrency} using CoinGecko price: ${cryptoPriceUSD}`);
return result;
}

private async convertCryptoToUsd(amount: string, fromCurrency: RampCurrency, decimals: number): Promise<string> {
// Try dynamic token price first
const dynamicPrice = getTokenUsdPrice(fromCurrency);
if (dynamicPrice !== undefined && dynamicPrice > 0) {
const result = new Big(amount).mul(dynamicPrice).toFixed(decimals);
logger.debug(`Converted ${amount} ${fromCurrency} to ${result} USD using dynamic price: ${dynamicPrice}`);
return result;
}

// Fall back to CoinGecko
logger.debug(`No dynamic price for ${fromCurrency}, falling back to CoinGecko`);
const tokenId = this.getCoinGeckoTokenId(fromCurrency);
if (!tokenId) {
throw new Error(`No CoinGecko token ID mapping for ${fromCurrency}`);
}

const cryptoPriceUSD = await this.getCryptoPrice(tokenId, "usd");
const result = new Big(amount).mul(cryptoPriceUSD).toFixed(decimals);
logger.debug(`Converted ${amount} ${fromCurrency} to ${result} USD using price: ${cryptoPriceUSD}`);
logger.debug(`Converted ${amount} ${fromCurrency} to ${result} USD using CoinGecko price: ${cryptoPriceUSD}`);
return result;
}
}
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/api/services/quote/core/squidrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ export function getTokenDetailsForEvmDestination(
});
}

console.log("Getting token details for:", finalOutputCurrency, "on network:", network);

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the console.log in this server-side path. It will spam production logs and bypasses the configured logger (which also controls log levels/format). Use logger.debug(...) (or remove entirely) instead.

Suggested change
console.log("Getting token details for:", finalOutputCurrency, "on network:", network);
logger.debug("Getting token details for EVM destination", {
finalOutputCurrency,
network
});

Copilot uses AI. Check for mistakes.

const tokenDetails = getOnChainTokenDetails(network, finalOutputCurrency);

if (!tokenDetails || !isEvmTokenDetails(tokenDetails)) {
Expand Down
5 changes: 4 additions & 1 deletion apps/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ dotenv.config({
path: [path.resolve(process.cwd(), ".env"), path.resolve(process.cwd(), "../.env")]
});

import { ApiManager, EvmClientManager, setLogger } from "@vortexfi/shared";
import { ApiManager, EvmClientManager, initializeEvmTokens, setLogger } from "@vortexfi/shared";
import { config, testDatabaseConnection } from "./config";
import cryptoService from "./config/crypto";
import app from "./config/express";
Expand Down Expand Up @@ -53,6 +53,9 @@ const initializeApp = async () => {
// Initialize RSA keys for webhook signing
cryptoService.initializeKeys();

// Initialize dynamic EVM tokens from SquidRouter API (falls back to static config on failure)
await initializeEvmTokens();

// Test database connection
await testDatabaseConnection();

Expand Down
32 changes: 16 additions & 16 deletions apps/frontend/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@
@plugin "daisyui";

:root {
--color-primary: #0f4dc0;
--color-primary-content: #fff;
--color-secondary: #f4f5f6;
--color-secondary-content: #58667e;
--color-accent: #db2777;
--color-accent-content: #000;
--color-neutral: #eff2f5;
--color-neutral-content: #58667e;
--color-base-100: #f5f9fa;
--color-base-200: #fff;
--color-base-300: #e3e7eb;
--color-base-content: #58667e;
--color-primary: oklch(0.45 0.2 260);
--color-primary-content: oklch(1 0 0);
--color-secondary: oklch(0.97 0.003 260);
--color-secondary-content: oklch(0.5 0.04 250);
--color-accent: oklch(0.55 0.22 350);
--color-accent-content: oklch(0 0 0);
--color-neutral: oklch(0.96 0.005 250);
--color-neutral-content: oklch(0.5 0.04 250);
--color-base-100: oklch(0.98 0.005 210);
--color-base-200: oklch(1 0 0);
--color-base-300: oklch(0.92 0.008 250);
--color-base-content: oklch(0.5 0.04 250);

--radius-field: 9px;
--border: 1px;

--text: #111;
--bg-modal: #fff;
--modal-border: #e5e5e5;
--text: oklch(0.15 0 0);
--bg-modal: oklch(1 0 0);
--modal-border: oklch(0.91 0 0);
--rounded-btn: 9px;
--btn-text-case: none;
}
Expand Down Expand Up @@ -75,7 +75,7 @@
.input-ghost[aria-readonly="true"]:focus-within {
background-color: transparent !important;
color: var(--color-base-content);
border-color: #0000;
border-color: oklch(0 0 0 / 0);
box-shadow: none;
}

Expand Down
2 changes: 2 additions & 0 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@tanstack/react-query": "^5.64.2",
"@tanstack/react-router": "^1.136.8",
"@tanstack/react-router-devtools": "^1.136.8",
"@tanstack/react-virtual": "^3.13.18",
"@tanstack/zod-adapter": "^1.144.0",
"@types/crypto-js": "^4.2.2",
"@vitejs/plugin-react": "^4.3.4",
Expand All @@ -56,6 +57,7 @@
"react-hook-form": "^7.65.0",
"react-i18next": "^15.4.1",
"react-toastify": "^11.0.5",
"react-window": "^2.2.5",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

react-window is listed in dependencies, but the code uses @tanstack/react-virtual and there are no react-window imports. Consider removing react-window here to keep dependencies minimal.

Suggested change
"react-window": "^2.2.5",

Copilot uses AI. Check for mistakes.
"stellar-sdk": "catalog:",
"tailwind-merge": "^3.1.0",
"tailwindcss": "^4.0.3",
Expand Down
38 changes: 0 additions & 38 deletions apps/frontend/src/assets/coins/DOT_ASSETHUB.svg

This file was deleted.

13 changes: 0 additions & 13 deletions apps/frontend/src/assets/coins/ETH.svg

This file was deleted.

37 changes: 0 additions & 37 deletions apps/frontend/src/assets/coins/ETH_ARBITRUM.svg

This file was deleted.

30 changes: 0 additions & 30 deletions apps/frontend/src/assets/coins/ETH_BASE.svg

This file was deleted.

37 changes: 0 additions & 37 deletions apps/frontend/src/assets/coins/ETH_BSC.svg

This file was deleted.

Loading