A kite floating above the text 'Introducing Kite' a modern Solana framework for TypeScript.
Blog/Development

Introducing Kite: the Modern Solana TypeScript Framework

4 min read

Today, we're excited to announce Kite, the modern TypeScript framework for both the browser and Node.js. Kite builds on the power of Solana web3.js version 2 while dramatically simplifying common tasks.


Why Kite?

Kite leverages the speed and elegance of Solana web3.js version 2 but allows you to do everyday Solana tasks in a single function.

Since Kite uses web3.js version 2 for the heavy lifting, the full features of web3.js version 2 are available. If you don't need Kite anymore, you can easily remove it and use plain web3.js version 2.

Kite is a web3.js v2 update of @solana-developers/helpers, the most popular high-level library for web3.js version 1, by the original author.

The Kite package includes updated versions of most of the original helpers, including contributions from Helius, the Solana Foundation, Anza, Turbin3, Unboxed Software, and StarAtlas.

The @solana-developers/helpers functions we don't yet have in Kite will be added soon.

Kite works both in the browser and node.js and has minimal dependencies.


What can I do with Kite?

Kite includes functions to do the following:

Wallets

SOL

Tokens

Transactions

Explorer

Comparing Kite to Solana web3.js 2:

Here's a quick example of making a token

Using Kite

Remember, Kite is just a framework on top of web3.js v2, so it uses the same types and underlying web3.js v2 features to do its work.

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));


Using Solana web3.js v2

...without 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`);

As you can see, without Kite, this would involve creating a transaction message with five instructions and the relevant options, signing the transaction message, and sending it to the RPC. In Kite, you run makeTokenMint and get the address of the new mint back.

Comparing Kite to Poseidon

Kite is a purely client-side library for browsers and node.js. Check out Poseidon if you're interested in building on-chain apps (e.g., smart contracts) using TypeScript

Contributing

While Kite is new, we're committed to growing it into a robust framework that makes Solana development more accessible to everyone.

We can help more developers build amazing things on Solana by simplifying common tasks and reducing boilerplate code.

Here's how you can help:

Try Kite Today

Ready to make your Solana development easier?

Get started with Kite:

Installing Kite
npm i @helius-dev/kite

Check out our GitHub repository for full documentation and examples.

Let's speed up Solana development together! 🪁

Related Articles

Subscribe to Helius

Stay up-to-date with the latest in Solana development and receive updates when we post