Intern/Project

[Intern] Squid api 연동 출발 및 도착 체인 트랜잭션 정보 조회 개발

dbfl9911 2024. 12. 18. 19:19
반응형

근무 내용

  • squid api 연동 출발 및 도착 체인 트랜잭션 정보 조회 개발 - timestamp 값, value 값
  • 브릿지 이후 tx들 데이터 불러오기

근무 결과


[ Squid router API 데이터 분석 ]

[예시로 조회되어야 할 해시값 목록]

이더리움↔bsc 간

https://api.0xsquid.com/v1/status?transactionId=0x155f30b344423b5ff4ece73f31742190064dd9652e7cf17802cee434f32e7cf2

아비트리움↔base 간

https://api.0xsquid.com/v1/status?transactionId=0x6ae843f0e6636d97fbf277ab0631a9e04a20e9e233682c4dce70891e17dc3817

https://api.0xsquid.com/v1/status?transactionId=0xb204e7774933acc79e42f415110aeb2012da6af4aa276aabdea7e8b973c68435

베이스↔bsc 간

https://api.0xsquid.com/v1/status?transactionId=0xfbd8c58aafb71f3980f77d3db2986b955b76f25ca8a065c6ac1d34ed738264c0

https://api.0xsquid.com/v1/status?transactionId=0x37f12211fc211b918e18aac0d110e194d5fcfdf5c262ddd0122664c769f0d935

베이스↔아비트리움 간

https://api.0xsquid.com/v1/status?transactionId=0x3e630a9cd1c20ecb8312a351e171616cadf1b8385d3ed12f022b58e31af97d79

https://api.0xsquid.com/v1/status?transactionId=0x61e81fc60887aa9557b06b5c4afbeda0ed660fbc7ca7c9731d2826ff9a1788cc


이더리움↔아비트리움 간

https://api.0xsquid.com/v1/status?transactionId=0xa60ce40abb28b640e01143b70eeb2f2e56205c5f6cb91ae5958c8dc85a139a33

 

아비트리움↔이더리움 간

예시 잘안나옴..

 

이더리움 ↔ 베이스 간

https://api.0xsquid.com/v1/status?transactionId=0xecc699b4be6d74ee66459947a06a4ed6b832ea3dfe5d8ad5d843397f8a3aa988

 

베이스 ↔ 이더리움 간

예시 잘안나옴..

 

 

 

[ base 타임스탬프 값 뜨지 않아 basescan api 연동해 개발 - 아래 api 사용 (파라미터로 block 값, api 값 필요) ]

https://api.basescan.org/api?module=block&action=getblockreward&blockno=24070597&apikey=9RJRI52SR9235UHJYDXCVG8TVXG4RP1MS9

timestamp 관련 코드 설명 -

  • Etherscan/Arbiscan: HTML 페이지에서 데이터를 파싱.
  • BaseScan: 블록 번호를 기반으로 API에서 타임스탬프 직접 조회.
private async fetchBaseTimestamp(blockNumber?: string): Promise {
    if (!blockNumber) return 0;
    try {
        const url = `https://api.basescan.org/api?module=block&action=getblockreward&blockno=${blockNumber}&apikey=${BASE_API_KEY}`;
        const { data } = await axios.get(url);
        return data?.result?.timeStamp ? parseInt(data.result.timeStamp) * 1000 : 0;
    } catch (error) {
        console.error(`Error fetching BaseScan timestamp for block: ${blockNumber}`, error);
        return 0;
    }
}

private async fetchTimestampFromUrl(transactionUrl: string): Promise {
    try {
        const response = await axios.get(transactionUrl);
        const $ = cheerio.load(response.data);
        const selector = transactionUrl.includes("etherscan.io")
            ? () => $('div#ContentPlaceHolder1_divTimeStamp').text().match(/Dec-\\d{2}-\\d{4} \\d{2}:\\d{2}:\\d{2} [AP]M UTC/)
            : transactionUrl.includes("arbiscan.io")
            ? () => $('span#showUtcLocalDate').attr('data-timestamp')
            : null;

        if (selector) {
            const result = selector();
            return result instanceof Array ? Date.parse(result[0] + ' UTC') : parseInt(result) * 1000;
        }

        return 0;
    } catch (error) {
        console.error(`Error fetching timestamp from URL: ${transactionUrl}`, error);
        return 0;
    }
}

파싱하는 방법은 페이지 html 구조 변경 시 정확한 데이터 불러오지 않는 위험성 있어, 아래 코드처럼 모두 체인별 api 불러오는 방식으로 변경

private async fetchChainTransactionDetails(chainName: string, transactionId: string): Promise {
    if (!transactionId) return { value: '0', hash: transactionId, timestamp: 0 };

    const chainApiMap = {
        ethereum: `https://api.etherscan.io/api?module=proxy&action=eth_getTransactionByHash&txhash=${transactionId}&apikey=${ETHEREUM_API_KEY}`,
        arbitrum: `https://api.arbiscan.io/api?module=proxy&action=eth_getTransactionByHash&txhash=${transactionId}&apikey=${ARBITRUM_API_KEY}`,
        base: `https://api.basescan.org/api?module=proxy&action=eth_getTransactionByHash&txhash=${transactionId}&apikey=${BASE_API_KEY}`,
    };

    const apiUrl = chainApiMap[chainName.toLowerCase()];
    if (!apiUrl) throw new Error(`Unsupported chain: ${chainName}`);

    try {
        const response = await axios.get(apiUrl);
        const tx = response.data?.result;
        if (!tx || !tx.blockNumber) return { value: '0', hash: transactionId, timestamp: 0 };

        const blockTimestamp = await this.fetchBlockTimestamp(chainName, tx.blockNumber);
        const value = tx.value ? (parseInt(tx.value, 16) / 1e18).toString() : '0';

        return { value, hash: transactionId, timestamp: blockTimestamp };
    } catch (error) {
        console.error(`Error fetching transaction details for ${transactionId} on ${chainName}`, error);
        return { value: '0', hash: transactionId, timestamp: 0 };
    }
}

private async fetchBlockTimestamp(chainName: string, blockNumber: string): Promise {
    const chainApiMap = {
        ethereum: `https://api.etherscan.io/api?module=block&action=getblockreward&blockno=${parseInt(blockNumber, 16)}&apikey=${ETHEREUM_API_KEY}`,
        arbitrum: `https://api.arbiscan.io/api?module=block&action=getblockreward&blockno=${parseInt(blockNumber, 16)}&apikey=${ARBITRUM_API_KEY}`,
        base: `https://api.basescan.org/api?module=block&action=getblockreward&blockno=${parseInt(blockNumber, 16)}&apikey=${BASE_API_KEY}`,
    };

    const apiUrl = chainApiMap[chainName.toLowerCase()];
    if (!apiUrl) throw new Error(`Unsupported chain: ${chainName}`);

    try {
        const response = await axios.get(apiUrl);
        return response.data?.result?.timeStamp ? parseInt(response.data.result.timeStamp) * 1000 : 0;
    } catch (error) {
        console.error(`Error fetching block timestamp for ${blockNumber} on ${chainName}`, error);
        return 0;
    }
}

반응형