Typescript로 Solana 프로그램 트랜잭션 파싱하기 - 파트 1/2
2024-10-29 11:45:26Typescript로 Solana 프로그램 트랜잭션 파싱하기 - 시작하기
최근 Kiryl의 트윗을 통해 중요한 영감을 받았습니다. 트윗 내용은 대중적인 DEFI 앱에 대해 오픈 소스 트랜잭션 파서를 요청하는 것이었습니다. 이로 인해 Solana 프로그램 트랜잭션을 번역하여 사람에게 이해하기 쉬운 형식으로 의미 있는 정보를 추출하는 방법을 설명하는 이 블로그를 작성하게 되었습니다. 여기에서는 Typescript를 사용하여 그 과정을 단계별로 설명하려 합니다.
프로젝트 설정: 시작하기 전에 준비해야 할 것
먼저, 프로젝트 디렉터리 "parser"를 생성하고 새로운 TypeScript 프로젝트를 초기화합니다. 이를 통해 기본적인 환경을 준비하게 됩니다.
mkdir parser
cd parser
npm init
npx tsc --init
의존성 설치
필요한 TypeScript와 기타 의존성을 설치합니다. 이를 통해 Solana와 상호작용하고 해시를 사용할 수 있습니다.
npm install typescript ts-node @types/node --save-dev
npm install @noble/hashes @solana/web3.js @coral-xyz/anchor@0.29.0
index.ts 파일 생성
프로젝트의 루트에 index.ts 파일을 생성합니다. 이 파일이 트랜잭션 파싱 로직을 담게 됩니다.
Anchor 프로그램 트랜잭션 디코딩
Anchor는 Solana 프로그램을 쉽고 빠르게 빌드하고 테스트할 수 있는 인기 있는 프레임워크입니다. 여기에 포함된 IDL(인터페이스 정의 언어)는 프로그램의 공용 인터페이스를 지정하며, 중요한 트랜잭션 디코딩 정보를 제공합니다. pump.fun 프로그램을 예제로 사용해 Anchor 프로그램 트랜잭션을 디코딩하는 방법을 설명합니다.
IDL과 트랜잭션 구조 이해하기
IDL은 프로그램 명령어와 이벤트에 대한 정보를 제공합니다. 이 섹션에서는 pump.fun 프로그램의 IDL 구조를 이해합니다.
{
"version": "string",
"name": "string",
"instructions": [],
"events": [],
"errors": [],
"metadata": { "address": "string" }
}
관련된 IDL 정보를 활용하여 트랜잭션의 명령어를 식별하고 필터링합니다.
가져올 데이터 항목
여기서는 특정 트랜잭션에서 추출할 다음과 같은 정보 항목을 정의합니다.
{
"solAmount": "string",
"tokenAmount": "string",
"mint": "string",
"type": "buy" | "sell",
"trader": "string"
}
위 항목을 추출하기 위해 Solana 메인넷에서 트랜잭션을 가져오고, 특정 명령어를 필터링하며 이벤트와 인스트럭션을 파싱하는 과정을 거칩니다.
트랜잭션 데이터 가져오기
Solana 메인넷에서 데이터 트랜잭션을 가져오는 예제를 작성합니다.
import { clusterApiUrl, Connection } from "@solana/web3.js"
const main = async () => {
const signature = "4XQZckrFKjaLHM68kJH7dpSPo2TCfMkwjYhLdcNRu5QdJTjAEehsS5UMaZKDXADD46d8v4XnuyuvLV36rNRTKhn7";
const connection = new Connection(clusterApiUrl("mainnet-beta"));
const transaction = await connection.getParsedTransaction(signature, { maxSupportedTransactionVersion: 0 });
console.log(transaction)
}
main()
위 코드로 트랜잭션 구조를 점검하고, 관련된 프로그램 명령어를 필터링합니다. 추출된 인스트럭션은 특정 구조를 갖습니다.
명령어 확인 및 필터링
비교적 쉬운 방법으로 파싱해야 하는 명령어를 찾아냅니다. 특정 명령어가 무엇인지 식별할 수 있는 discriminator를 추출합니다.
const discriminator = Buffer.from(sha256('global:<instruction name>').slice(0, 8));
이제 buy와 sell 명령어를 식별할 수 있습니다.
const buyDiscriminator = Buffer.from(sha256('global:buy').slice(0, 8));
const sellDiscriminator = Buffer.from(sha256('global:sell').slice(0, 8));
const buySellIxs = pumpIxs?.filter(ix => {
const discriminator = bs58.decode((ix as PartiallyDecodedInstruction).data).subarray(0, 8);
return discriminator.equals(buyDiscriminator) || discriminator.equals(sellDiscriminator)
})
명령어 인자 정의
마지막으로 borsh를 사용하여 buy와 sell 명령어 인자의 스키마를 만듭니다.
const tradeSchema = borsh.struct([
borsh.u64("discriminator"),
borsh.u64("amount"),
borsh.u64("solEstimate")
])
이 과정은 트랜잭션 디코딩의 핵심으로, IDL 정보를 바탕으로 정확한 인자를 파싱하고 이해하는데 중점을 둡니다.
다음 단계: 경쟁사의 트랜잭션 비교 분석
이 블로그의 다음 파트에서는 Raydium 트랜잭션을 활용하여 네이티브 Rust 프로그램 트랜잭션을 분석합니다. Anchor와 비교하여 어떤 차이점이 있는지 비교하며, DEFI 앱 트랜잭션을 더욱 철저히 이해할 수 있도록 자세한 설명을 추가할 예정입니다.
결론 및 참고 자료
Solana에서의 트랜잭션은 복잡해 보이지만, 잘 정의된 프로세스를 통해 의미 있는 데이터를 효율적으로 추출할 수 있습니다. Typescript와 새로운 웹3 라이브러리를 이용하여 Solana 네트워크와 효율적으로 상호작용하는 방법을 탐구해 보십시오.
위의 자료를 참고하여 더욱 깊이 있는 이해를 돕기를 바랍니다.