Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions src/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,21 @@ export const Chains = {
publicRPCs: ['https://rpc.plasma.to', 'https://plasma.drpc.org'],
explorer: 'https://plasmascan.to/',
},
UNICHAIN: {
chainId: 130,
name: 'Unichain',
ids: ['unichain'],
nativeCurrency: { symbol: 'ETH', name: 'Ethereum' },
wToken: '0x4200000000000000000000000000000000000006',
publicRPCs: [
'https://mainnet.unichain.org',
'https://unichain-rpc.publicnode.com',
'https://unichain.drpc.org',
'https://0xrpc.io/uni',
'https://unichain.therpc.io',
],
explorer: 'https://uniscan.xyz/',
},
ETHEREUM_GOERLI: {
chainId: 5,
name: 'Ethereum Goerli',
Expand Down
3 changes: 1 addition & 2 deletions src/services/prices/price-sources/alchemy-price-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ export class AlchemyPriceSource implements IPriceSource {
} else if (Array.isArray(onChains)) {
this.supported = onChains;
} else {
const chains = alchemySupportedChains({ onlyFree: onChains.allInTier === 'free tier' });
this.supported = onChains.except ? chains.filter((chain) => !onChains.except!.includes(chain)) : chains;
this.supported = alchemySupportedChains();
}
}

Expand Down
19 changes: 4 additions & 15 deletions src/services/providers/provider-sources/alchemy-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChainId } from '@types';
import { BaseHttpProvider, HttpProviderConfig } from './base/base-http-provider';
import { ALCHEMY_NETWORKS } from '@shared/alchemy';

export type AlchemySupportedChains = AlchemyDefaultChains | ChainId[];
type AlchemyDefaultChains = { allInTier: 'free tier' | 'paid tier'; except?: ChainId[] };
export type AlchemySupportedChains = ChainId[];

export class AlchemyProviderSource extends BaseHttpProvider {
private readonly key: string;
Expand All @@ -17,8 +16,7 @@ export class AlchemyProviderSource extends BaseHttpProvider {
} else if (Array.isArray(onChains)) {
this.supported = onChains;
} else {
const chains = alchemySupportedChains({ onlyFree: onChains.allInTier === 'free tier' });
this.supported = onChains.except ? chains.filter((chain) => !onChains.except!.includes(chain)) : chains;
this.supported = alchemySupportedChains();
}
}

Expand All @@ -31,17 +29,8 @@ export class AlchemyProviderSource extends BaseHttpProvider {
}
}

export function alchemySupportedChains(args?: { onlyFree?: boolean }): ChainId[] {
return Object.entries(ALCHEMY_NETWORKS)
.filter(
([
_,
{
rpc: { tier },
},
]) => tier === 'free' || !args?.onlyFree
)
.map(([chainId]) => Number(chainId));
export function alchemySupportedChains(): ChainId[] {
return Object.entries(ALCHEMY_NETWORKS).map(([chainId]) => Number(chainId));
}

export function buildAlchemyRPCUrl({ chainId, apiKey, protocol }: { chainId: ChainId; apiKey: string; protocol: 'https' | 'wss' }) {
Expand Down
52 changes: 25 additions & 27 deletions src/shared/alchemy.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
import { Chains } from '@chains';
import { ChainId } from '@types';

export const ALCHEMY_NETWORKS: Record<
ChainId,
{ key: string; rpc: { tier: 'free' | 'paid' }; price: { supported: boolean }; blocks: { supported: boolean } }
> = {
[Chains.ETHEREUM.chainId]: { key: 'eth-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: true } },
[Chains.ETHEREUM_SEPOLIA.chainId]: { key: 'eth-sepolia', rpc: { tier: 'free' }, price: { supported: false }, blocks: { supported: false } },
[Chains.OPTIMISM.chainId]: { key: 'opt-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: true } },
[Chains.ARBITRUM.chainId]: { key: 'arb-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: true } },
[Chains.POLYGON.chainId]: { key: 'polygon-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: true } },
[Chains.POLYGON_MUMBAI.chainId]: { key: 'polygon-mumbai', rpc: { tier: 'free' }, price: { supported: false }, blocks: { supported: false } },
[Chains.ASTAR.chainId]: { key: 'astar-mainnet', rpc: { tier: 'free' }, price: { supported: false }, blocks: { supported: false } },
[Chains.BLAST.chainId]: { key: 'blast-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: true } },
[Chains.BNB_CHAIN.chainId]: { key: 'bnb-mainnet', rpc: { tier: 'paid' }, price: { supported: true }, blocks: { supported: true } },
[Chains.AVALANCHE.chainId]: { key: 'avax-mainnet', rpc: { tier: 'paid' }, price: { supported: true }, blocks: { supported: true } },
[Chains.FANTOM.chainId]: { key: 'fantom-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: false } },
[Chains.METIS_ANDROMEDA.chainId]: { key: 'metis-mainnet', rpc: { tier: 'paid' }, price: { supported: true }, blocks: { supported: false } },
export const ALCHEMY_NETWORKS: Record<ChainId, { key: string; price: { supported: boolean }; blocks: { supported: boolean } }> = {
[Chains.ETHEREUM.chainId]: { key: 'eth-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.ETHEREUM_SEPOLIA.chainId]: { key: 'eth-sepolia', price: { supported: false }, blocks: { supported: false } },
[Chains.OPTIMISM.chainId]: { key: 'opt-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.ARBITRUM.chainId]: { key: 'arb-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.POLYGON.chainId]: { key: 'polygon-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.POLYGON_MUMBAI.chainId]: { key: 'polygon-mumbai', price: { supported: false }, blocks: { supported: false } },
[Chains.ASTAR.chainId]: { key: 'astar-mainnet', price: { supported: false }, blocks: { supported: false } },
[Chains.BLAST.chainId]: { key: 'blast-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.BNB_CHAIN.chainId]: { key: 'bnb-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.AVALANCHE.chainId]: { key: 'avax-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.FANTOM.chainId]: { key: 'fantom-mainnet', price: { supported: true }, blocks: { supported: false } },
[Chains.METIS_ANDROMEDA.chainId]: { key: 'metis-mainnet', price: { supported: true }, blocks: { supported: false } },
[Chains.POLYGON_ZKEVM.chainId]: {
key: 'polygonzkevm-mainnet',
rpc: { tier: 'free' },
price: { supported: true },
blocks: { supported: false },
},
[Chains.BASE.chainId]: { key: 'base-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: true } },
[Chains.GNOSIS.chainId]: { key: 'gnosis-mainnet', rpc: { tier: 'paid' }, price: { supported: true }, blocks: { supported: false } },
[Chains.SCROLL.chainId]: { key: 'scroll-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: false } },
[Chains.opBNB.chainId]: { key: 'opbnb-mainnet', rpc: { tier: 'paid' }, price: { supported: true }, blocks: { supported: false } },
[Chains.MANTLE.chainId]: { key: 'mantle-mainnet', rpc: { tier: 'free' }, price: { supported: false }, blocks: { supported: false } },
[Chains.ROOTSTOCK.chainId]: { key: 'rootstock-mainnet', rpc: { tier: 'free' }, price: { supported: false }, blocks: { supported: false } },
[Chains.LINEA.chainId]: { key: 'linea-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: false } },
[Chains.SONIC.chainId]: { key: 'sonic-mainnet', rpc: { tier: 'free' }, price: { supported: false }, blocks: { supported: false } },
[Chains.ZK_SYNC_ERA.chainId]: { key: 'zksync-mainnet', rpc: { tier: 'free' }, price: { supported: true }, blocks: { supported: true } },
[Chains.CELO.chainId]: { key: 'celo-mainnet', rpc: { tier: 'free' }, price: { supported: false }, blocks: { supported: true } },
[Chains.BASE.chainId]: { key: 'base-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.GNOSIS.chainId]: { key: 'gnosis-mainnet', price: { supported: true }, blocks: { supported: false } },
[Chains.SCROLL.chainId]: { key: 'scroll-mainnet', price: { supported: true }, blocks: { supported: false } },
[Chains.opBNB.chainId]: { key: 'opbnb-mainnet', price: { supported: true }, blocks: { supported: false } },
[Chains.MANTLE.chainId]: { key: 'mantle-mainnet', price: { supported: false }, blocks: { supported: false } },
[Chains.ROOTSTOCK.chainId]: { key: 'rootstock-mainnet', price: { supported: false }, blocks: { supported: false } },
[Chains.LINEA.chainId]: { key: 'linea-mainnet', price: { supported: true }, blocks: { supported: false } },
[Chains.SONIC.chainId]: { key: 'sonic-mainnet', price: { supported: false }, blocks: { supported: false } },
[Chains.ZK_SYNC_ERA.chainId]: { key: 'zksync-mainnet', price: { supported: true }, blocks: { supported: true } },
[Chains.CELO.chainId]: { key: 'celo-mainnet', price: { supported: false }, blocks: { supported: true } },
[Chains.PLASMA.chainId]: { key: 'plasma-mainnet', price: { supported: false }, blocks: { supported: false } },
[Chains.UNICHAIN.chainId]: { key: 'unichain-mainnet', price: { supported: false }, blocks: { supported: false } },
};
3 changes: 3 additions & 0 deletions src/shared/defi-llama.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const CHAIN_ID_TO_KEY: Record<ChainId, Lowercase<string>> = {
[Chains.MANTLE.chainId]: 'mantle',
[Chains.METIS_ANDROMEDA.chainId]: 'metis',
[Chains.SONIC.chainId]: 'sonic',
[Chains.PLASMA.chainId]: 'plasma',
[Chains.UNICHAIN.chainId]: 'unichain',
};

const KEY_TO_CHAIN_ID: Record<string, ChainId> = Object.fromEntries(
Expand Down Expand Up @@ -249,6 +251,7 @@ export class DefiLlamaClient {
const DEFI_LLAMA_NATIVE_TOKEN = '0x0000000000000000000000000000000000000000';
const MAPPINGS: Record<Lowercase<TokenId>, Lowercase<TokenId>> = {
'polygon:0x2791bca1f2de4661ed88a30c99a7a9449aa84174': 'polygon:0x3c499c542cef5e3811e1192ce70d8cc03d5c3359', // Bridged USDC (USDC.e): Native USDC
[`polygon:${DEFI_LLAMA_NATIVE_TOKEN}`]: 'polygon:0x0000000000000000000000000000000000001010', // POL
'arbitrum:0xff970a61a04b1ca14834a43f5de4533ebddb5cc8': 'arbitrum:0xaf88d065e77c8cc2239327c5edb3a432268e5831', // Bridged USDC (USDC.e): Native USDC
'optimism:0x7f5c764cbc14f9669b88837ca1490cca17c31607': 'optimism:0x0b2c639c533813f4aa9d7837caf62653d097ff85', // Bridged USDC (USDC.e): Native USDC
};
Expand Down
6 changes: 3 additions & 3 deletions test/integration/services/prices/price-sources.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,17 @@ describe('Token Price Sources', () => {
source.getHistoricalPrices({
tokens: tokens.map((token) => ({
...token,
timestamp: 1736294400, // Wednesday, January 8, 2025 12:00:00 AM
timestamp: 1760054400, // Sat, 10 Oct 2025 00:00:00 GMT
})),
config: { timeout: '10s' },
searchWidth: undefined,
}),
validation: ({ [1736294400]: { price, closestTimestamp: timestamp } }) => {
validation: ({ [1760054400]: { price, closestTimestamp: timestamp } }) => {
expect(typeof price).to.equal('number');
expect(typeof timestamp).to.equal('number');
},
});
const from = 1736294400; // Wednesday, January 8, 2025 12:00:00 AM
const from = 1760054400; // Sat, 10 Oct 2025 00:00:00 GMT
const span = 5;
const period = '1d';
queryTest({
Expand Down