Skip to content

Commit 7c1a552

Browse files
authored
add SUI to Allbridge Core (#428)
* add SUI to Allbridge Core * fix Allbridge Core event data
1 parent 9bd59a5 commit 7c1a552

File tree

7 files changed

+107
-57
lines changed

7 files changed

+107
-57
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"@defillama/sdk": "^5.0.170",
4141
"@fastify/cors": "^9.0.1",
4242
"@graphql-typed-document-node/core": "^3.2.0",
43+
"@mysten/sui": "^1.43.0",
4344
"@solana/web3.js": "^1.87.3",
4445
"async-retry": "^1.3.1",
4546
"axios": "^0.21.0",
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import axios, { AxiosResponse } from 'axios';
2+
import { BigNumber } from 'ethers';
3+
import { EventData } from '../../utils/types';
4+
5+
interface AnalyticsEvent {
6+
blockTime: number;
7+
txHash: string;
8+
from: string;
9+
to: string;
10+
token: string;
11+
amount: string;
12+
isDeposit: boolean;
13+
}
14+
15+
export async function getEventsFromAnalyticsApi(
16+
chainCode: string,
17+
fromBlock: number,
18+
fromTimestampMs: number,
19+
toBlock: number,
20+
toTimestampMs: number
21+
): Promise<EventData[]> {
22+
const from = new Date(fromTimestampMs).toISOString();
23+
const to = new Date(toTimestampMs).toISOString();
24+
25+
let response: AxiosResponse<AnalyticsEvent[]>;
26+
try {
27+
response = await axios.get<AnalyticsEvent[]>(
28+
`https://core.api.allbridgecoreapi.net/analytics/inflows?chain=${chainCode}&from=${from}&to=${to}`
29+
);
30+
} catch (e) {
31+
console.error(`Error fetching ${chainCode} events`, e);
32+
return [];
33+
}
34+
35+
return response.data.map((event) => {
36+
const blockTimeMs = event.blockTime * 1000;
37+
return {
38+
blockNumber: interpolateNumber(fromBlock, fromTimestampMs, toBlock, toTimestampMs, blockTimeMs),
39+
txHash: event.txHash,
40+
from: event.from,
41+
to: event.to,
42+
token: event.token,
43+
amount: BigNumber.from(event.amount),
44+
isDeposit: event.isDeposit,
45+
timestamp: blockTimeMs,
46+
}
47+
});
48+
}
49+
50+
function interpolateNumber(x1: number, y1: number, x2: number, y2: number, y: number): number {
51+
const x = x1 + (x2 - x1) / (y2 - y1) * (y - y1);
52+
return Math.round(x);
53+
}

src/adapters/allbridge-core/index.ts

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import axios, { AxiosResponse } from 'axios';
21
import { BigNumber } from 'ethers';
32
import { BridgeAdapter, PartialContractEventParams } from "../../helpers/bridgeAdapter.type";
43
import { Chain } from "@defillama/sdk/build/general";
@@ -7,6 +6,8 @@ import { fromHex } from 'tron-format-address';
76
import { getConnection } from '../../helpers/solana';
87
import { getTxDataFromEVMEventLogs } from "../../helpers/processTransactions";
98
import { getTxDataFromTronEventLogs } from './eventParsing';
9+
import { getEventsFromAnalyticsApi } from './analyticsApi';
10+
import { getClient as getSuiClient } from '../../helpers/sui';
1011

1112
const adapterName = "allbridge-core";
1213

@@ -59,6 +60,10 @@ const lpAddresses = {
5960
[chain: string]: string[];
6061
};
6162

63+
const suiFullTokenAddressMap: Record<string, string> = {
64+
"0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7": "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
65+
};
66+
6267
const constructParams = (chain: string) => {
6368
let eventParams = [] as PartialContractEventParams[];
6469
const lps = lpAddresses[chain];
@@ -111,21 +116,6 @@ const constructParams = (chain: string) => {
111116
getTxDataFromEVMEventLogs(adapterName, chain as Chain, fromBlock, toBlock, eventParams);
112117
};
113118

114-
interface SolanaEvent {
115-
blockTime: number;
116-
txHash: string;
117-
from: string;
118-
to: string;
119-
token: string;
120-
amount: string;
121-
isDeposit: boolean;
122-
}
123-
124-
function interpolateNumber(x1: number, y1: number, x2: number, y2: number, y: number): number {
125-
const x = x1 + (x2 - x1) / (y2 - y1) * (y - y1);
126-
return Math.round(x);
127-
}
128-
129119
const getSolanaEvents = async (fromSlot: number, toSlot: number): Promise<EventData[]> => {
130120
const connection = getConnection();
131121
const timestampFrom = await connection.getBlockTime(fromSlot);
@@ -134,28 +124,18 @@ const getSolanaEvents = async (fromSlot: number, toSlot: number): Promise<EventD
134124
if (!timestampFrom || !timestampTo) {
135125
return [];
136126
}
137-
const from = new Date(timestampFrom * 1000).toISOString();
138-
const to = new Date(timestampTo * 1000).toISOString();
127+
return await getEventsFromAnalyticsApi('SOL', fromSlot, timestampFrom * 1000, toSlot, timestampTo * 1000);
128+
};
139129

140-
let response: AxiosResponse<SolanaEvent[]>;
141-
try {
142-
response = await axios.get<SolanaEvent[]>(
143-
`https://core.api.allbridgecoreapi.net/analytics/inflows?chain=SOL&from=${from}&to=${to}`
144-
);
145-
} catch (e) {
146-
console.error("Error fetching Solana events", e);
147-
return [];
148-
}
130+
const getSuiEvents = async (fromCheckpointNumber: number, toCheckpointNumber: number): Promise<EventData[]> => {
131+
const client = getSuiClient();
132+
const fromCheckpoint = await client.getCheckpoint({ id: fromCheckpointNumber.toString() });
133+
const fromTimestampMs = Number(fromCheckpoint.timestampMs);
134+
const toCheckpoint = await client.getCheckpoint({ id: toCheckpointNumber.toString() });
135+
const toTimestampMs = Number(toCheckpoint.timestampMs);
149136

150-
return response.data.map((event) => ({
151-
blockNumber: interpolateNumber(fromSlot, timestampFrom, toSlot, timestampTo, event.blockTime),
152-
txHash: event.txHash,
153-
from,
154-
to,
155-
token: event.token,
156-
amount: BigNumber.from(event.amount),
157-
isDeposit: event.isDeposit,
158-
}));
137+
const eventData = await getEventsFromAnalyticsApi('SUI', fromCheckpointNumber, fromTimestampMs, toCheckpointNumber, toTimestampMs);
138+
return eventData.map((data) => ({ ...data, token: suiFullTokenAddressMap[data.token] ?? data.token }));
159139
};
160140

161141
function constructTronParams() {
@@ -225,6 +205,7 @@ const adapter: BridgeAdapter = {
225205
sonic: constructParams("sonic"),
226206
unichain: constructParams("unichain"),
227207
solana: getSolanaEvents,
208+
sui: getSuiEvents,
228209
};
229210

230211
export default adapter;

src/helpers/sui.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
// import {
2-
// SuiClient,
3-
// SuiTransactionBlockResponse,
4-
// getFullnodeUrl,
5-
// PaginatedTransactionResponse,
6-
// } from "@mysten/sui.js/client";
1+
import {
2+
SuiClient,
3+
SuiTransactionBlockResponse,
4+
getFullnodeUrl,
5+
PaginatedTransactionResponse,
6+
} from "@mysten/sui/client";
77

8-
// export const getClient = () => {
9-
// const url = process.env.SUI_RPC ?? getFullnodeUrl("mainnet");
10-
// return new SuiClient({ url });
11-
// };
8+
export const getClient = () => {
9+
const url = process.env.SUI_RPC ?? getFullnodeUrl("mainnet");
10+
return new SuiClient({ url });
11+
};
1212

1313
// export const getTransactionBlocks = async (
1414
// fromCheckpoint: number,

src/utils/blocks.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getLatestBlock as getLatestBlockSdk, lookupBlock as lookupBlockSdk } from "@defillama/sdk/build/util";
2-
// import { getClient } from "../helpers/sui";
2+
import { getClient } from "../helpers/sui";
33
import { tronGetLatestBlock } from "../helpers/tron";
44
import { getConnection } from "../helpers/solana";
55
import { Chain } from "@defillama/sdk/build/general";
@@ -11,6 +11,7 @@ import {
1111
ibcGetBlockFromTimestamp,
1212
} from "../adapters/ibc";
1313
import bridgeNetworkData from "../data/bridgeNetworkData";
14+
1415
const retry = require("async-retry");
1516

1617
const connection = getConnection();
@@ -21,8 +22,8 @@ async function getLatestSlot() {
2122

2223
export async function getLatestBlockNumber(chain: string, bridge?: string): Promise<number> {
2324
if (chain === "sui") {
24-
// const client = getClient();
25-
// return Number(await client.getLatestCheckpointSequenceNumber());
25+
const client = getClient();
26+
return Number(await client.getLatestCheckpointSequenceNumber());
2627
} else if (chain === "solana") {
2728
return await getLatestSlot();
2829
} else if (chain === "tron") {
@@ -65,10 +66,10 @@ async function getBlockTime(slotNumber: number) {
6566

6667
export async function getLatestBlock(chain: string, bridge?: string): Promise<{ number: number; timestamp: number }> {
6768
if (chain === "sui") {
68-
// const client = getClient();
69-
// const seqNumber = await client.getLatestCheckpointSequenceNumber();
70-
// const { timestampMs } = await client.getCheckpoint({ id: seqNumber });
71-
// return { number: Number(seqNumber), timestamp: Number(timestampMs) };
69+
const client = getClient();
70+
const seqNumber = await client.getLatestCheckpointSequenceNumber();
71+
const { timestampMs } = await client.getCheckpoint({ id: seqNumber });
72+
return { number: Number(seqNumber), timestamp: Math.floor(Number(timestampMs) / 1000) };
7273
} else if (chain === "tron") {
7374
return await tronGetLatestBlock();
7475
} else if (chain === "solana") {

src/utils/prices.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { PRICES_API } from "./constants";
2+
23
const axios = require("axios");
34
const retry = require("async-retry");
45

@@ -29,7 +30,7 @@ const NAME_MAPPING: Record<string, string> = {
2930
export const getLlamaPrices = async (tokens: string[], timestamp?: number): Promise<Record<string, any>> => {
3031
const finalPrices: { [key: string]: any } = {};
3132
let remainingTokens = tokens.map((token) => {
32-
const [prefix, id] = token.split(":");
33+
const [prefix, id] = splitOnce(token, ":");
3334
const mappedPrefix = NAME_MAPPING[prefix] || prefix;
3435
return `${mappedPrefix}:${id}`;
3536
});
@@ -46,9 +47,22 @@ export const getLlamaPrices = async (tokens: string[], timestamp?: number): Prom
4647

4748
return Object.fromEntries(
4849
Object.entries(finalPrices).map(([key, value]) => {
49-
const [prefix, id] = key.split(":");
50+
const [prefix, id] = splitOnce(key, ":");
5051
const originalPrefix = Object.entries(NAME_MAPPING).find(([, mappedName]) => mappedName === prefix)?.[0];
5152
return [`${originalPrefix || prefix}:${id}`, value];
5253
})
5354
);
5455
};
56+
57+
function splitOnce(input: string, separator: string): string[] {
58+
const index = input.indexOf(separator);
59+
60+
if (index === -1) {
61+
return [input];
62+
}
63+
64+
const part1 = input.substring(0, index);
65+
const part2 = input.substring(index + separator.length);
66+
return [part1, part2];
67+
}
68+

src/utils/provider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
// import { getClient } from "../helpers/sui";
1+
import { getClient } from "../helpers/sui";
22
import { getProvider as getLlamaProvider } from "@defillama/sdk";
33
import { getConnection } from "../helpers/solana";
44

55
export function getProvider(chain: string) {
66
if (chain === "sui") {
7-
// return getClient();
7+
return getClient();
88
} else if (chain === "solana") {
99
return getConnection();
1010
}

0 commit comments

Comments
 (0)