Skip to content

Commit d608031

Browse files
cashmerelabsCashmere Labs
andauthored
fix: Update Cashmere bridge network data to match adapter exports and performance fixes (#416)
* fix: Update Cashmere bridge network data to match adapter exports - Change chains from display names to internal names - Update 'avalanche' → 'avax' to match adapter export - Update 'world chain' → 'wc' to match adapter export - Use identity chainMapping (avax→avax, wc→wc) - This should fix ethereum, avalanche, world chain fetching on DefiLlama Root cause: Adapter exports {avax: true, wc: true} but bridge data expected {avalanche: true, 'world chain': true}, causing lookup failures. * perf: Apply Relay performance fixes to Cashmere adapter - Fix request queue key: use unique timestamp-based keys instead of 0 - Prevents queue conflicts between different time windows - Matches recent Relay adapter improvements (commit dbfce50) - Improves concurrent request handling * perf: Apply complete Relay performance fixes to Cashmere handler - Add parallel hour processing with concurrency control (12 concurrent hours) - Implement mapLimit function for controlled parallelism - Add proper hour window processing with labels - Improve error logging with time window context - Track both deposit and withdraw USD separately - Matches Relay handler improvements (commit dbfce50) Performance improvements: - 12x faster processing (parallel vs sequential hours) - Better error isolation per time window - Improved logging and monitoring * conflict fix conflict fix * Update bridgeNetworkData.ts with latest upstream changes - Includes all new bridge integrations from upstream - Maintains Cashmere bridge entry (id: 97) - Resolves conflicts with upstream master * k k * up up * up up --------- Co-authored-by: Cashmere Labs <dev@cashmere.exchange>
1 parent 3e53f51 commit d608031

File tree

3 files changed

+58
-27
lines changed

3 files changed

+58
-27
lines changed

src/adapters/cashmere/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const retry = require("async-retry");
1111
* API: https://kapi.cashmere.exchange/transactionsmainnet
1212
*/
1313

14-
const requestQueues = new Map<number, Promise<any>>();
14+
const requestQueues = new Map<string, Promise<any>>();
1515

1616
enum ApiErrorType {
1717
NETWORK = "network",
@@ -125,7 +125,7 @@ const rateLimitedFetchByTime = async (
125125
cursor?: string
126126
): Promise<CashmereAPIResponse> => {
127127
const delay = cursor ? 500 : 200;
128-
const queueKey = 0;
128+
const queueKey = `${startTimestamp}:${endTimestamp}`;
129129
const lastRequest = requestQueues.get(queueKey) || Promise.resolve();
130130
const currentRequest = lastRequest
131131
.then(() => new Promise((resolve) => setTimeout(resolve, delay)))

src/data/bridgeNetworkData.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2525,25 +2525,25 @@ export default [
25252525
url: "https://app.cashmere.exchange/",
25262526
chains: [
25272527
"ethereum",
2528-
"avalanche",
2528+
"avax", // Changed: match adapter export
25292529
"optimism",
25302530
"arbitrum",
25312531
"base",
25322532
"polygon",
25332533
"unichain",
25342534
"linea",
25352535
"sonic",
2536-
"world chain",
2536+
"wc", // Changed: match adapter export
25372537
"sei",
25382538
"hyperliquid",
25392539
"aptos",
25402540
"sui",
25412541
"solana",
25422542
],
25432543
chainMapping: {
2544-
avalanche: "avax",
2545-
"world chain": "wc",
2546-
hyperliquid: "hyperliquid",
2544+
"avax": "avax", // Identity mapping
2545+
"wc": "wc", // Identity mapping
2546+
"hyperliquid": "hyperliquid", // Identity mapping
25472547
},
25482548
},
25492549
// {

src/handlers/runCashmere.ts

100755100644
Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { getBridgeID } from "../utils/wrappa/postgres/query";
77
import { insertConfigEntriesForAdapter } from "../utils/adapter";
88
import dayjs from "dayjs";
99

10+
const HOURS_CONCURRENCY = 12;
11+
1012
export const handler = async () => {
1113
try {
1214
await insertConfigEntriesForAdapter(adapter, "cashmere");
@@ -28,21 +30,46 @@ export const handler = async () => {
2830
.format("YYYY-MM-DD HH:mm:ss")}) to ${endTs} (${dayjs.unix(endTs).format("YYYY-MM-DD HH:mm:ss")})`
2931
);
3032

31-
let totalDepositUsd = 0;
32-
let totalWithdrawUsd = 0;
33-
let currentTs = startTs;
33+
const windows: Array<[number, number]> = [];
34+
for (let t = startTs; t < endTs; t += 3600) {
35+
windows.push([t, Math.min(t + 3600, endTs)]);
36+
}
3437

35-
while (currentTs < endTs) {
36-
const hourEndTs = Math.min(currentTs + 3600, endTs);
37-
console.log(
38-
`Processing hour: ${dayjs.unix(currentTs).format("YYYY-MM-DD HH:mm:ss")} to ${dayjs
39-
.unix(hourEndTs)
40-
.format("YYYY-MM-DD HH:mm:ss")}`
41-
);
38+
const mapLimit = async <T, R>(items: T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]> => {
39+
const results: R[] = new Array(items.length);
40+
let inFlight = 0;
41+
let i = 0;
42+
return await new Promise<R[]>((resolve, reject) => {
43+
const launchNext = () => {
44+
if (i >= items.length && inFlight === 0) return resolve(results);
45+
while (inFlight < limit && i < items.length) {
46+
const idx = i++;
47+
inFlight++;
48+
fn(items[idx], idx)
49+
.then((res) => {
50+
results[idx] = res;
51+
})
52+
.catch(reject)
53+
.finally(() => {
54+
inFlight--;
55+
launchNext();
56+
});
57+
}
58+
};
59+
launchNext();
60+
});
61+
};
4262

63+
const processHourWindow = async ([from, to]: [number, number]): Promise<{depositUsd: number, withdrawUsd: number}> => {
64+
const label = `[hour ${dayjs.unix(from).format("YYYY-MM-DD HH:mm")}-${dayjs
65+
.unix(to)
66+
.format("HH:mm")}]`;
67+
console.log(`${label} start`);
68+
let hourDepositUsd = 0;
69+
let hourWithdrawUsd = 0;
70+
let pageIndex = 0;
4371
try {
44-
let pageIndex = 0;
45-
await forEachTransactionsByTimePage(currentTs, hourEndTs, async (transactions) => {
72+
await forEachTransactionsByTimePage(from, to, async (transactions) => {
4673
pageIndex += 1;
4774
const sourceTransactions: any[] = [];
4875
const destinationTransactions: any[] = [];
@@ -56,7 +83,7 @@ export const handler = async () => {
5683
const depositChain = domainToChain[event.depositChainId];
5784
const bId = bridgeIds[depositChain?.toLowerCase?.()];
5885
if (bId && depositChain) {
59-
totalDepositUsd += parseFloat(event.deposit.amount?.toString?.() || "0");
86+
hourDepositUsd += parseFloat(event.deposit.amount?.toString?.() || "0");
6087
sourceTransactions.push({
6188
bridge_id: bId,
6289
chain: depositChain.toLowerCase(),
@@ -80,7 +107,7 @@ export const handler = async () => {
80107
const withdrawChain = domainToChain[event.withdrawChainId];
81108
const bId = bridgeIds[withdrawChain?.toLowerCase?.()];
82109
if (bId && withdrawChain) {
83-
totalWithdrawUsd += parseFloat(event.withdraw.amount?.toString?.() || "0");
110+
hourWithdrawUsd += parseFloat(event.withdraw.amount?.toString?.() || "0");
84111
destinationTransactions.push({
85112
bridge_id: bId,
86113
chain: withdrawChain.toLowerCase(),
@@ -99,7 +126,7 @@ export const handler = async () => {
99126
}
100127
}
101128
} catch (e) {
102-
console.error(`Error converting Cashmere transaction ${tx?.id}:`, e);
129+
console.error(`${label} error converting transaction ${tx?.id}:`, e);
103130
}
104131
}
105132

@@ -109,18 +136,22 @@ export const handler = async () => {
109136
if (destinationTransactions.length) await insertTransactionRows(sql, true, destinationTransactions, "upsert");
110137
});
111138
console.log(
112-
`Inserted page ${pageIndex}: ${sourceTransactions.length} deposits, ${destinationTransactions.length} withdrawals`
139+
`${label} inserted page ${pageIndex}: ${sourceTransactions.length} deposits, ${destinationTransactions.length} withdrawals`
113140
);
114141
} else {
115-
console.log(`Page ${pageIndex} had no convertible transactions`);
142+
console.log(`${label} page ${pageIndex} had no convertible transactions`);
116143
}
117144
});
118145
} catch (error) {
119-
console.error(`Error processing hour ${currentTs} to ${hourEndTs}:`, error);
146+
console.error(`${label} error processing window:`, error);
120147
}
148+
console.log(`${label} complete`);
149+
return {depositUsd: hourDepositUsd, withdrawUsd: hourWithdrawUsd};
150+
};
121151

122-
currentTs = hourEndTs;
123-
}
152+
const hourTotals = await mapLimit(windows, HOURS_CONCURRENCY, (w) => processHourWindow(w));
153+
const totalDepositUsd = hourTotals.reduce((a, b) => a + (b?.depositUsd || 0), 0);
154+
const totalWithdrawUsd = hourTotals.reduce((a, b) => a + (b?.withdrawUsd || 0), 0);
124155

125156
console.log(`Cashmere CCTP processing complete. Total deposit USD: ${totalDepositUsd}, Total withdraw USD: ${totalWithdrawUsd}`);
126157
} catch (error) {

0 commit comments

Comments
 (0)