Intro to solana/web3.js 🌅
Tags: javascript, tutorial
Published: 2022-10-15 11:58:49


[@solana/web3.js](https://solana-labs.github.io/solana-web3.js/index.html) 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](https://solana-labs.github.io/solana-web3.js/index.html).

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](https://solanacookbook.com/#contributing).

## 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 ](https://www.jsonrpc.org/specification) specification. So e.g. you can fetch wallet address just using CURL:

```shell
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
}
```

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

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

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

let balance = await connection.getBalance(publicKey);
```

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0i77yb9cjd8pq8bhg6sb.png)


[Link to FigJam file](https://www.figma.com/file/jyX6w2ufOwQRNGfHPC1FHx/solana%2Fweb3.js?node-id=0%3A1)


## 🔌 Connection

The first thing to use is [Connection](https://solana-labs.github.io/solana-web3.js/classes/Connection.html) 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](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) by your choice and setup [JSON-RPC 2.0 Client](https://github.com/tedeh/jayson) to transfer your commands into json-rpc messages server can understand.

You can use one of [Solana's RPC-nodes](https://docs.solana.com/cluster/rpc-endpoints) (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. 

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

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:

```js
/**
 * 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;
}
```
 
So you can use such `requestAirdrop` fn with `Connection` to request some SOL:

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

// You'll also need to confirm this TX
await connection.confirmTransaction(signature);
```

### Overview

Connection methods can be grouped in such groups of interests.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gbc37ymro205ghoshkny.png)

[Link to FigJam file](https://www.figma.com/file/jyX6w2ufOwQRNGfHPC1FHx/solana%2Fweb3.js?node-id=0%3A1)


### Useful Methods

[getParsedAccountInfo()](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#getParsedAccountInfo) & [getAccountInfo()](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#getAccountInfo) are very useful to fetch info about accounts, like to find what tokens or NFTs hold some wallet.

[getBalance()](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#getBalance)  returns amount of SOL hold in the account.

[confirmTransaction()](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#confirmTransaction) & [sendTransaction()](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#sendTransaction) are used when you have created some Transaction and want to send it to the blockchain.

[getLatestBlockhash()](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#getLatestBlockhash) returns info about recent blockhash which you may use while creating new TX. 

```js
const recentBlockhash = await connection.getLatestBlockhash();

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

[getProgramAccounts()](https://solana-labs.github.io/solana-web3.js/classes/Connection.html#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()](https://solana-labs.github.io/solana-web3.js/classes/Keypair.html#generate) function and then using its properties [publicKey](https://solana-labs.github.io/solana-web3.js/classes/Keypair.html#publicKey) & [secretKey](https://solana-labs.github.io/solana-web3.js/classes/Keypair.html#secretKey). 

```js
let keypair = Keypair.generate();
```

And `publicKey` itself returns instance of [PublicKey](https://solana-labs.github.io/solana-web3.js/classes/PublicKey.html) class with some handy methods like [toBase58()](https://solana-labs.github.io/solana-web3.js/classes/PublicKey.html#toBase58) or [toString()](https://solana-labs.github.io/solana-web3.js/classes/PublicKey.html#toString) as well as [findProgramAddress()](https://solana-labs.github.io/solana-web3.js/classes/PublicKey.html#findProgramAddress) to find available address for provided seed text.

## 🧾 Transaction & TransactionInstruction

[Transaction](https://solana-labs.github.io/solana-web3.js/classes/Transaction.html) object can be used to create new TX for the Solana network which you populate with exact instructions using [TransactionInstruction](https://solana-labs.github.io/solana-web3.js/classes/TransactionInstruction.html) class.

```js
const transferTransaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: fromKeypair.publicKey,
    toPubkey: toKeypair.publicKey,
    lamports: 10000000,
  })
);
```

Useful methods:

[add()](https://solana-labs.github.io/solana-web3.js/classes/Transaction.html#add) will add one or more instructions to newly created TX

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

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

[sign()](https://solana-labs.github.io/solana-web3.js/classes/Transaction.html#sign) will sign the Transaction with the specified signers.

[getEstimatedFee()](https://solana-labs.github.io/solana-web3.js/classes/Transaction.html#getEstimatedFee) get the estimated fee associated with a transaction:

```js
const fees = await transaction.getEstimatedFee(connection);
```

The TX can be sign, send and confirm with globally available method [sendAndConfirmTransaction()](https://solana-labs.github.io/solana-web3.js/modules.html#sendAndConfirmTransaction)

```js
await web3.sendAndConfirmTransaction(connection, transaction, [fromWallet]);
```

Each TX will be populated with TX Instructions using [TransactionInstruction](https://solana-labs.github.io/solana-web3.js/classes/TransactionInstruction.html) 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"),
  })
);
```


## 🛠 SystemProgram

[SystemProgram](https://solana-labs.github.io/solana-web3.js/classes/SystemProgram.html) 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.

```js
const transferTransaction = new Transaction().add(
  SystemProgram.transfer({
    fromPubkey: fromKeypair.publicKey,
    toPubkey: toKeypair.publicKey,
    lamports: lamportsToSend,
  })
);
```

Also, it may be useful to create new accounts with [createAccount()](https://solana-labs.github.io/solana-web3.js/classes/SystemProgram.html#createAccount) & [createAccountWithSeed()](https://solana-labs.github.io/solana-web3.js/classes/SystemProgram.html#createAccountWithSeed):

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

const createAccountTransaction = new Transaction().add(
  SystemProgram.createAccount(createAccountParams)
);
```

## 🧰 More

Examples above taken from [Solana Cookbook](https://solanacookbook.com/#contributing). Check it for more.

If you want to interact with tokens on Solana network you will need to use different [@solana/spl-token](https://solana-labs.github.io/solana-program-library/token/js/index.html) package additionally.