Intro to solana/web3.js 🌅

jamland

andy_801 🔫🇺🇦

Posted on October 15, 2022

Intro to solana/web3.js 🌅

@solana/web3.js SDK is a main interface to communicate with Solana network for your JavaScript application. It is written in TypeScript and it enforces you to use TS instead of JS same as Solana in general.

It doesn't really have detailed text on each class and method and practices, so the best way to learn it might be just to research through its auto-generated docs.

This text is try to summarize things as I get to know it and a brief description web3.js main functionality. Code examples for common use-cases can be found on 📙 Solana Cookbook.

What it does?

solana/web3.js is doing 2 main things to simplify your coding life. First it handles communication with Solana nodes and second it provides useful representations & utilities to work with Solana concepts, like Account, Transaction, Instruction, SystemProgram, PublicKey, Keypair, etc.

Communication with Solana

If you want to read/write data to Solana blockchain you need to use language it understands. Communication with Solana built around nodes in form of HTTP requests using the JSON-RPC 2.0 specification. So e.g. you can fetch wallet address just using CURL:

curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getBalance",
    "params": [
      "CBBUMHRmbVUck99mTCip5sHP16kzGj3QTYB8K3XxwmQx"
    ]
  }
'

response >>>>
{
  "jsonrpc": "2.0",
  "result": {
    "context": { 
      "apiVersion": "1.13.2", 
      "slot":169434407
    },
    "value": 21087922374
  },
  "id":1
}
Enter fullscreen mode Exit fullscreen mode

solana/web3.js gives a convenient interface for the RPC methods, so same request can be done with these JS code lines:

const connection = new Connection("https://api.devnet.solana.com");

const address = "CBBUMHRmbVUck99mTCip5sHP16kzGj3QTYB8K3XxwmQx";
const publicKey = new PublicKey(address);

let balance = await connection.getBalance(publicKey);
Enter fullscreen mode Exit fullscreen mode

Main Functionality

Library have plenty of classes and methods, but there are some to be used from program to program and can be put to this pretty short list of classes and their methods displayed in the next mindmap graph.

solana/web3.js graph

Link to FigJam file

🔌 Connection

The first thing to use is Connection object. It is also the most charged with different methods.

When you create Connection object the constructor is trying establish connection with provided RPC node using HTTP or WebSockets API by your choice and setup JSON-RPC 2.0 Client to transfer your commands into json-rpc messages server can understand.

You can use one of Solana's RPC-nodes (mainnet, devnet, testnet) but them very limited in number of requests you can send, so google to find some you can use for free or for the money.

const connection = new Connection(
  "https://api.devnet.solana.com",
  "confirmed"
);
Enter fullscreen mode Exit fullscreen mode

Then this object describes a bunch of methods which are wrappers over rpc methods. It also handles proper arguments passing and error handling for each such method. For example:

/**
 * Request an allocation of lamports to the specified address
 */
async requestAirdrop(
  to: PublicKey,
  lamports: number,
): Promise<TransactionSignature> {
  const unsafeRes = await this._rpcRequest('requestAirdrop', [
    to.toBase58(),
    lamports,
  ]);
  const res = create(unsafeRes, RequestAirdropRpcResult);
  if ('error' in res) {
    throw new SolanaJSONRPCError(
      res.error,
      `airdrop to ${to.toBase58()} failed`,
    );
  }
  return res.result;
}
Enter fullscreen mode Exit fullscreen mode

So you can use such requestAirdrop fn with Connection to request some SOL:

const airdropSignature = await connection.requestAirdrop(
  fromKeypair.publicKey,
  LAMPORTS_PER_SOL
);

// You'll also need to confirm this TX
await connection.confirmTransaction(signature);
Enter fullscreen mode Exit fullscreen mode

Overview

Connection methods can be grouped in such groups of interests.

Image description

Link to FigJam file

Useful Methods

getParsedAccountInfo() & getAccountInfo() are very useful to fetch info about accounts, like to find what tokens or NFTs hold some wallet.

getBalance() returns amount of SOL hold in the account.

confirmTransaction() & sendTransaction() are used when you have created some Transaction and want to send it to the blockchain.

getLatestBlockhash() returns info about recent blockhash which you may use while creating new TX.

const recentBlockhash = await connection.getLatestBlockhash();

const transaction = new Transaction({
  recentBlockhash: recentBlockhash.blockhash,
}).add(
  SystemProgram.transfer({
    fromPubkey: payer.publicKey,
    toPubkey: payee.publicKey,
    lamports: 10,
  })
);
Enter fullscreen mode Exit fullscreen mode

getProgramAccounts() fetch all the accounts owned by the specified program id. Can be used to find NFT accounts created by Candy Machine for example.

🔐 Keypair & PublicKey

Many of the different actions you can take with the various Solana libraries require a Keypair or Wallet. You can use one from connected wallet or you can generate keypair yourself with generate() function and then using its properties publicKey & secretKey.

let keypair = Keypair.generate();
Enter fullscreen mode Exit fullscreen mode

And publicKey itself returns instance of PublicKey class with some handy methods like toBase58() or toString() as well as findProgramAddress() to find available address for provided seed text.

🧾 Transaction & TransactionInstruction

Transaction object can be used to create new TX for the Solana network which you populate with exact instructions using TransactionInstruction class.

const transferTransaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: fromKeypair.publicKey,
    toPubkey: toKeypair.publicKey,
    lamports: 10000000,
  })
);
Enter fullscreen mode Exit fullscreen mode

Useful methods:

add() will add one or more instructions to newly created TX

const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({ 
  units: 1000000 
});

const transaction = new Transaction()
  .add(modifyComputeUnits)
  .add(
    SystemProgram.transfer({
      fromPubkey: payer.publicKey,
      toPubkey: toAccount,
      lamports: 10000000,
    })
  );
Enter fullscreen mode Exit fullscreen mode

sign() will sign the Transaction with the specified signers.

getEstimatedFee() get the estimated fee associated with a transaction:

const fees = await transaction.getEstimatedFee(connection);
Enter fullscreen mode Exit fullscreen mode

The TX can be sign, send and confirm with globally available method sendAndConfirmTransaction()

await web3.sendAndConfirmTransaction(connection, transaction, [fromWallet]);
Enter fullscreen mode Exit fullscreen mode

Each TX will be populated with TX Instructions using TransactionInstruction object:

await transferTransaction.add(
  new TransactionInstruction({
    keys: [{ pubkey: fromKeypair.publicKey, isSigner: true, isWritable: true }],
    data: Buffer.from("Data to send in transaction", "utf-8"),
    programId: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),
  })
);
Enter fullscreen mode Exit fullscreen mode

🛠 SystemProgram

SystemProgram is factory class for transactions to interact with the System program.

You might need to interact with SystemProgram when you want to transfer some SOL.

const transferTransaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: fromKeypair.publicKey,
    toPubkey: toKeypair.publicKey,
    lamports: lamportsToSend,
  })
);
Enter fullscreen mode Exit fullscreen mode

Also, it may be useful to create new accounts with createAccount() & createAccountWithSeed():

const createAccountParams = {
  fromPubkey: fromPubkey.publicKey,
  newAccountPubkey: newAccountPubkey.publicKey,
  lamports: rentExemptionAmount,
  space,
  programId: SystemProgram.programId,
};

const createAccountTransaction = new Transaction().add(
  SystemProgram.createAccount(createAccountParams)
);
Enter fullscreen mode Exit fullscreen mode

🧰 More

Examples above taken from Solana Cookbook. Check it for more.

If you want to interact with tokens on Solana network you will need to use different @solana/spl-token package additionally.

💖 💪 🙅 🚩
jamland
andy_801 🔫🇺🇦

Posted on October 15, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related