읽는 데 8분
개요
지갑과 관련된 모든 거래 내역을 한 번에 조회해야 할 때가 있으신가요? 캔디 머신과 관련된 모든 발행 거래 내역을 확인하고 싶으신가요? 아니면 NFT의 거래 내역을 확인하고 싶으신가요? Solana getSignaturesForAddress 메서드는 거래 내역을 손쉽게 확인할 수 있게 해주는 다용도 도구입니다.
동영상 튜토리얼을 선호하시나요? 노아와 함께 15분 만에 Solana .js를 사용하여 Solana 로그를 가져오는 방법을 배워보세요.
주요 업무
이 가이드에서는 Solana 흥미진진한 세계를 깊이 있게 탐구해 보겠습니다! 특정 주소(지갑, 프로그램 ID, 토큰 민트 등)를 조회하고, 해당 주소와 관련된 모든 거래 내역을 찾아볼 수 있는 간단한 스크립트를 직접 만들어 보실 것입니다.
준비물
- Node.js (버전 16.15 이상)
- 실 설치 완료
- Solana
- Solana)의 기본 트랜잭션에 대한 실습. 지식을 다시 다지고 싶다면, Solana 트랜잭션을 보내는 방법’에 대한 초보자 가이드를 읽어보세요.
- 자바스크립트 지식
그럼 시작해 볼까요!
환경 설정하기
터미널에서 다음 명령어를 실행하여 새로운 프로젝트 디렉터리와 log.js 파일을 생성하세요:
mkdir get_sol_tx
cd get_sol_tx
echo > log.js
Solana 종속성을 설치합니다:
yarn init -y
yarn add @solana/web3.js@1
또는
npm init -y
npm install --save @solana/web3.js@1
원하는 코드 편집기에서 log.js 파일을 열고, 1행에서 solana.js를 require한 다음 이를 상수 **solanaWeb3:
**에 저장하세요.
const solanaWeb3 = require(solana.js');
검색하고자 하는 주소를 지정하세요:
const searchAddress = 'YOUR_ADDRESS_HERE'; //예시 'vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg'
참고: 이는 Solana 상의 유효한 주소라면 무엇이든 가능합니다 Solana 예: 지갑 주소, 민트 주소, 프로그램 주소). 아직 주소가 없다면 'vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg'를 예시로 사용할 수 있습니다.
자, 이제 요리할 준비가 다 됐네요!
Quicknode 에 연결하기
Solana 개발을 하려면 네트워크에 endpoint API endpoint 필요합니다. 공개 노드를 사용하거나 자체 인프라를 구축 및 관리하셔도 무방하지만, 응답 속도를 8배 더 빠르게 하고 싶으시다면 번거로운 작업은 저희에게 맡겨 주세요.
Solana ( Solana ) 프로젝트의 50% 이상이 Quicknode Solana 이유를 확인하고 Quicknode 여기에서 무료로 가입하세요.
저희는 Solana Devnet에서 노드를 실행할 예정이지만, 여러분은 필요에 맞는 노드를 실행하시면 됩니다. HTTP Provider 링크를 복사하세요:

log.js 로 돌아가서 상수 endpoint 라는 상수를 생성하고, 여기에 Quicknode 할당하세요. 다음 줄에서 이 상수를 Connection 함수의 매개변수로 전달하고, 그 결과를 solanaConnection이라는 또 다른 상수에 저장하세요:
const endpoint = 'https://example.solana-devnet.quiknode.pro/000000/';
const solanaConnection = new solanaWeb3.Connection(endpoint);
좋아요! 이제 검색 기능을 만들 준비가 되셨네요.
트랜잭션 쿼리 생성
getSignaturesForAddress 메서드가 여기서 대부분의 주요 작업을 처리할 것입니다. 작동 방식은 다음과 같습니다:
다음과 같이 두 개의 매개변수를 받습니다:
- 검색할 주소 (필수): 조회하려는 공개 키
- 옵션 (선택 사항): 다음 3가지 선택적 항목을 포함하는 객체:
- 이전: 특정 거래 서명 이전 시점으로 거슬러 올라가 검색을 시작합니다.
- after: 특정 트랜잭션 서명 이후의 시점을 기준으로 앞으로 검색을 시작합니다.
- limit: 반환할 트랜잭션의 최대 개수 (최대값 및 기본값은 1,000입니다)
이 메서드는 주요 거래 정보를 포함하는 타입 객체인 ConfirmedSignatureInfo의 배열을 반환하는 Promise를 반환합니다:
- 서명(거래 ID),
- slot 및 blockTime (트랜잭션이 처리된 시점을 확인하기 위해),
- 오류(있는 경우), 그리고
- 메모 (해당 거래와 관련된 메모가 있는 경우)
두 개의 매개변수( address 와 numTx)를 받는 새로운 비동기 함수 getTransactions를 정의하세요.
함수 내부에서 solanaConnection의 새 인스턴스에 대해 getSignaturesForAddress 메서드를 호출하고, 그 결과를 transactionList 변수에 저장합니다:
const getTransactions = async(address, numTx) => {
const pubKey = new solanaWeb3.PublicKey(address);
let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, {limit:numTx});
}
그러면 검색 조건에 맞는 모든 거래 내역이 담긴 배열이 반환될 것입니다. 결과를 읽기 쉽게 출력해 봅시다.
getTransactions 내부에서 forEach 루프를 생성하여 각 트랜잭션에 대한 정보를 기록합니다:
const getTransactions = async(address, numTx) => {
const pubKey = new solanaWeb3.PublicKey(address);
let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, {limit:numTx});
transactionList.forEach((transaction, i) => {
const date = new Date(transaction.blockTime*1000);
console.log(`Transaction No: ${i+1}`);
console.log(`Signature: ${transaction.signature}`);
console.log(`Time: ${date}`);
console.log(`Status: ${transaction.confirmationStatus}`);
console.log(("-").repeat(20));
})
}
코드를 실행해 보세요!
모든 설정이 올바르게 되어 있다면, 함수를 호출하여 결과를 확인할 수 있을 것입니다! 다음 코드를 log.js 파일 맨 아래에 추가하세요:
getTransactions(searchAddress,3);
이제 터미널에서 다음 명령어를 입력하세요:
node log.js
다음과 같은 화면이 표시될 것입니다:

와! 꽤 쉽죠? 여러 가지 지갑과 NFT 민트 주소, 캔디 머신 ID를 자유롭게 테스트해 보세요. 이 방법을 사용하면 비슷한 결과가 나온다는 것을 알 수 있는데, 덕분에 다양한 용도로 활용하기에 정말 편리합니다.
축하합니다! 트랜잭션을 성공적으로 처리하셨습니다....여기서 멈추셔도 되지만, 그 트랜잭션 서명으로 또 어떤 작업을 할 수 있는지 알고 싶으시다면 계속 읽어보세요! 👇
거래 내역 분석
이제 거래 내역에 대한 유용한 기본 정보는 파악했지만, 각 거래에서 정확히 어떤 작업이 수행되었을까요? Solana getParsedTransaction 메서드를 사용하면 훨씬 더 자세한 정보를 얻을 수 있습니다.
getParsedTransaction 메서드는 확인되었거나 최종 확정된 트랜잭션 서명을 인수로 받아 ParsedTransactionWithMeta 객체를 반환합니다:
export type ParsedTransactionWithMeta = {
/** The slot during which the transaction was processed */
slot: number;
/** The details of the transaction */
transaction: ParsedTransaction;
/** Metadata produced from the transaction */
meta: ParsedTransactionMeta | null;
/** The unix timestamp of when the transaction was processed */
blockTime?: number | null;
/** The version of the transaction message */
version?: TransactionVersion;
};
여기에는 많은 정보가 담겨 있지만, 이 입문 가이드에서는 그 내용을 모두 다루지는 않을 것입니다. 다만, 이러한 객체들과 어떻게 상호작용할 수 있는지에 대한 예시를 하나 보여드리고자 합니다.
getTransactions 함수 내에서 signatureList와 transactionDetails라는 두 개의 새로운 변수를 선언해 봅시다. transactionList를 매핑하여 서명 목록을 생성하고, getParsedTransactions를 호출하여 해당 서명을 통해 각 거래에 대한 세부 정보를 생성할 것입니다:
const getTransactions = async(address, numTx) => {
const pubKey = new solanaWeb3.PublicKey(address);
let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, {limit:numTx});
//Add this code
let signatureList = transactionList.map(transaction=>transaction.signature);
let transactionDetails = await solanaConnection.getParsedTransactions(signatureList, {maxSupportedTransactionVersion:0});
//--END of new code
transactionList.forEach((transaction, i) => {
const date = new Date(transaction.blockTime*1000);
console.log(`Transaction No: ${i+1}`);
console.log(`Signature: ${transaction.signature}`);
console.log(`Time: ${date}`);
console.log(`Status: ${transaction.confirmationStatus}`);
console.log(("-").repeat(20));
})
}
프로미스가 반환되면, transactionDetails는 ParsedTransactionWithMeta 객체들로 구성된 배열을 반환합니다. 그 안에서 유용한 정보를 찾아보도록 합시다.
특정 거래와 관련해 우리가 상호작용한 모든 프로그램이나 스마트 계약을 찾아보고 싶다고 가정해 봅시다. 원래의 forEach 루프 내부에서, date 변수를 선언한 뒤에 transactionInstructions라는 새로운 변수를 만들어 봅시다:
const transactionInstructions = transactionDetails[i].transaction.메시지.지시사항;
이렇게 하면 인덱스 i를 사용하여 루프 내에서 쿼리 중인 거래에 대한 상세 거래 정보를 찾아낼 수 있습니다. 각 거래에는 여러 개의 명령어나 프로그램 반복이 포함될 수 있으므로, 해당 거래 내의 각 프로그램 상호작용을 가져오기 위해 또 다른 루프가 필요합니다. 루프 내부에서 confirmationStatus 로그 출력 뒤에 다음 코드를 추가하세요:
transactionInstructions.forEach((instruction, n)=>{
console.log(`---Instructions ${n+1}: ${instruction.programId.toString()}`);
})
여기서 우리가 하고 있는 일은, 각 트랜잭션에 대해 해당 트랜잭션 명령을 검토하고, 프로그램 이름(있는 경우)과 프로그램 ID를 기록하는 것입니다.
최종 함수는 다음과 같이 되어야 합니다:
const getTransactions = async(address, numTx) => {
const pubKey = new solanaWeb3.PublicKey(address);
let transactionList = await solanaConnection.getSignaturesForAddress(pubKey, {limit:numTx});
let signatureList = transactionList.map(transaction=>transaction.signature);
let transactionDetails = await solanaConnection.getParsedTransactions(signatureList, {maxSupportedTransactionVersion:0});
transactionList.forEach((transaction, i) => {
const date = new Date(transaction.blockTime*1000);
const transactionInstructions = transactionDetails[i].transaction.message.instructions;
console.log(`Transaction No: ${i+1}`);
console.log(`Signature: ${transaction.signature}`);
console.log(`Time: ${date}`);
console.log(`Status: ${transaction.confirmationStatus}`);
transactionInstructions.forEach((instruction, n)=>{
console.log(`---Instructions ${n+1}: ${instruction.programId.toString()}`);
})
console.log(("-").repeat(20));
})
}
이제 스크립트를 다시 실행해 보세요. 터미널에서 다음 명령어를 입력하세요:
node log.js
다음과 같은 화면이 표시될 것입니다:

정말 잘하셨어요! 이제 거래 결과에 우리가 이용했던 다양한 프로그램에 대한 세부 정보가 포함되었습니다!
원하신다면, 여기에서 주소를 검색하여 결과를 Solana 비교해 보실 수 있습니다(페이지 오른쪽 상단에서 네트워크를 변경하여 동일한 네트워크에서 검색하고 있는지 확인하세요).
마무리
정말 잘하셨습니다! 이제 Solana 흥미진진한 세계를 속속들이 살펴보셨네요!
이 내용에 대해서는 향후 가이드에서 더 자세히 다룰 예정이지만, 지금 바로 더 알아보고 싶으시다면 transactionDetails 배열을 활용해 다음과 같은 유사한 쿼리를 실행해 보세요.
- transactionDetails[i].meta
- transactionDetails[i].transaction.message.accountKeys
이러한 개념을 실제로 적용해 보시려면, 여기에서 저희가 제공하는 다른 Solana 확인해 보세요.
Solana 더 많은 기사와 가이드를 받아보시려면 뉴스레터를 구독해 주세요. 의견이 있으시면 트위터를 통해 언제든지 연락해 주세요. 또한, 여러분이 만나볼 수 있는 가장 멋진 개발자들이 모인 저희 디스코드 커뮤니티 서버에서 언제든지 저희와 대화를 나눌 수 있습니다 :)
