신규: Helius가 Light Protocol을 인수했습니다
'Kite 소개'라는 문구 위로 연이 떠 있는 모습. Kite는 현대적인 Solana TypeScript 프레임워크입니다.
블로그/개발

Kite 소개: 현대적인 Solana TypeScript 프레임워크

개발자 교육X의 Mike MacCanaLinkedIn의 Mike MacCana
읽는 데 4분
목차

    오늘 브라우저와 Node.js를 위한 현대적인 TypeScript 프레임워크 Kite를 소개합니다. Kite는 Solana web3.js 버전 2의 강력한 기능을 기반으로 하면서 일반적인 작업을 획기적으로 간소화합니다.

    왜 Kite인가요?

    Kite는 Solana web3.js 버전 2의 속도와 우아함을 활용하면서도 일상적인 Solana 작업을 단일 함수로 처리할 수 있게 해줍니다.

    Kite는 핵심 작업에 web3.js 버전 2를 사용하므로 web3.js 버전 2의 모든 기능을 이용할 수 있습니다. Kite가 더 이상 필요하지 않다면 손쉽게 제거하고 web3.js 버전 2를 그대로 사용하면 됩니다.

    Kite는 원저자가 가장 인기 있는 web3.js 버전 1용 고수준 라이브러리인 @solana-developers/helpers를 web3.js v2에 맞게 업데이트한 프로젝트입니다.

    Kite 패키지에는 Helius, Solana Foundation, Anza, Turbin3, Unboxed Software, StarAtlas의 기여를 포함해 기존 헬퍼 대부분의 업데이트된 버전이 들어 있습니다.

    아직 Kite에 포함되지 않은 @solana-developers/helpers 함수도 곧 추가할 예정입니다.

    Kite는 브라우저와 node.js에서 모두 작동하며 의존성이 최소화되어 있습니다.

    Kite로 무엇을 할 수 있나요?

    Kite에는 다음 작업을 수행하는 함수가 포함되어 있습니다.

    지갑

    SOL

    토큰

    트랜잭션

    Explorer

    • Solana Explorer 링크 가져오기 — RPC를 사용해 트랜잭션, 블록 또는 주소를 표시하는 데 필요한 모든 세부 정보가 담긴 링크를 한 단계로 가져옵니다.

    Kite와 Solana web3.js 2 비교:

    토큰을 생성하는 간단한 예시입니다.

    Kite 사용

    Kite는 web3.js v2 기반의 프레임워크이므로 동일한 타입과 기반 web3.js v2 기능을 사용해 작업을 수행합니다.

    Making a token (including metadata) using Kite
    import { connect } from "@helius-dev/kite";
    const connection = connect();
    const mintAddress = await connection.makeTokenMint(
      mintAuthority,
      6,
      "My Token",
      "MTKN",
      "https://example.com/metadata.json",
      {
        description: "A sample token",
        website: "https://example.com",
      },
    );
    console.log(connection.getExplorerLink(mintAddress));

    Solana web3.js v2 사용

    ...Kite 없이 사용합니다!

    Making a token using web3.js version 2
    import {
      airdropFactory,
      appendTransactionMessageInstructions,
      createSolanaRpc,
      createSolanaRpcSubscriptions,
      createTransactionMessage,
      generateKeyPairSigner,
      getSignatureFromTransaction,
      lamports,
      pipe,
      sendAndConfirmTransactionFactory,
      setTransactionMessageFeePayerSigner,
      setTransactionMessageLifetimeUsingBlockhash,
      signTransactionMessageWithSigners,
      some,
    } from "@solana/web3.js";
    import { getCreateAccountInstruction } from "@solana-program/system";
    import {
      getInitializeMintInstruction,
      getMintSize,
      TOKEN_2022_PROGRAM_ADDRESS,
      extension,
      getInitializeMetadataPointerInstruction,
      getInitializeTokenMetadataInstruction,
      tokenMetadataField,
      getUpdateTokenMetadataFieldInstruction,
    } from "@solana-program/token-2022";
    
    const rpc = createSolanaRpc("http://127.0.0.1:8899");
    const rpcSubscriptions = createSolanaRpcSubscriptions("ws://127.0.0.1:8900");
    
    const feePayer = await generateKeyPairSigner();
    console.log(feePayer.address);
    const mint = await generateKeyPairSigner();
    
    await airdropFactory({ rpc, rpcSubscriptions })({
      recipientAddress: feePayer.address,
      lamports: lamports(1_000_000_000n),
      commitment: "confirmed",
    });
    
    const balance = await rpc.getBalance(feePayer.address).send();
    console.log("balance:", balance.value);
    
    const metadataPointerExtension = extension("MetadataPointer", {
      authority: some(feePayer.address),
      metadataAddress: some(mint.address),
    });
    
    const tokenMetadataExtension = extension("TokenMetadata", {
      updateAuthority: some(feePayer.address),
      mint: mint.address,
      name: "OPOS",
      symbol: "OPOS",
      uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json",
      additionalMetadata: new Map<string, string>([["description", "Only Possible On Solana"]]),
    });
    
    const spaceWithoutMetadata = BigInt(getMintSize([metadataPointerExtension]));
    
    const spaceWithMetadata = BigInt(getMintSize([metadataPointerExtension, tokenMetadataExtension]));
    
    const rent = await rpc.getMinimumBalanceForRentExemption(spaceWithMetadata).send();
    
    const createAccountInstruction = getCreateAccountInstruction({
      payer: feePayer,
      newAccount: mint,
      lamports: rent,
      space: spaceWithoutMetadata,
      programAddress: TOKEN_2022_PROGRAM_ADDRESS,
    });
    
    const initializeMetadataPointerInstruction = getInitializeMetadataPointerInstruction({
      mint: mint.address,
      authority: feePayer.address,
      metadataAddress: mint.address,
    });
    
    const initializeMintInstruction = getInitializeMintInstruction({
      mint: mint.address,
      decimals: 2,
      mintAuthority: feePayer.address,
    });
    
    const initializeTokenMetadataInstruction = getInitializeTokenMetadataInstruction({
      metadata: mint.address,
      updateAuthority: feePayer.address,
      mint: mint.address,
      mintAuthority: feePayer,
      name: tokenMetadataExtension.name,
      symbol: tokenMetadataExtension.symbol,
      uri: tokenMetadataExtension.uri,
    });
    
    const updateTokenMetadataInstruction = getUpdateTokenMetadataFieldInstruction({
      metadata: mint.address,
      updateAuthority: feePayer,
      field: tokenMetadataField("Key", ["description"]),
      value: "Only Possible On Solana",
    });
    
    const instructions = [
      createAccountInstruction,
      initializeMetadataPointerInstruction,
      initializeMintInstruction,
      initializeTokenMetadataInstruction,
      updateTokenMetadataInstruction,
    ];
    
    const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
    
    const transactionMessage = pipe(
      createTransactionMessage({ version: 0 }),
      (message) => setTransactionMessageFeePayerSigner(feePayer, message),
      (message) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message),
      (message) => appendTransactionMessageInstructions(instructions, message),
    );
    
    const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
    
    const transactionSignature = getSignatureFromTransaction(signedTransaction);
    
    await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
      commitment: "confirmed",
      skipPreflight: true,
    });
    
    console.log("Transaction Signature:", `https://explorer.solana.com/tx/${transactionSignature}?cluster=custom`);
    

    보시다시피 Kite가 없다면 명령 5개와 관련 옵션으로 트랜잭션 메시지를 만들고, 해당 메시지에 서명한 후 RPC로 전송해야 합니다. Kite에서는 makeTokenMint를 실행하면 새 민트의 주소가 반환됩니다.

    Kite와 Poseidon 비교

    Kite는 브라우저와 node.js를 위한 순수 클라이언트 측 라이브러리입니다. TypeScript로 온체인 앱(예: 스마트 계약)을 빌드하려면 Poseidon을 확인해 보세요. 

    기여하기

    Kite는 새로 출시됐지만, 누구나 Solana 개발에 더 쉽게 접근할 수 있도록 견고한 프레임워크로 발전시켜 나가겠습니다.

    일반적인 작업을 간소화하고 반복 코드를 줄이면 더 많은 개발자가 Solana에서 놀라운 결과물을 만들 수 있습니다.

    다음과 같은 방법으로 도울 수 있습니다.

    지금 Kite를 사용해 보세요

    Solana 개발을 더 간편하게 만들 준비가 되셨나요?

    Kite를 시작하세요.

    Installing Kite
    npm i @helius-dev/kite

    전체 문서와 예시는 GitHub 저장소에서 확인하세요.

    함께 Solana 개발 속도를 높여 보세요! 🪁

    Helius 구독하기

    최신 Solana 개발 소식을 확인하고 새 게시물 알림을 받아보세요