Intro to solana/web3.js 🌅
andy_801 🔫🇺🇦
Posted on October 15, 2022
@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
}
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);
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.
🔌 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"
);
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;
}
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);
Overview
Connection methods can be grouped in such groups of interests.
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,
})
);
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();
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,
})
);
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,
})
);
sign() will sign the Transaction with the specified signers.
getEstimatedFee() get the estimated fee associated with a transaction:
const fees = await transaction.getEstimatedFee(connection);
The TX can be sign, send and confirm with globally available method sendAndConfirmTransaction()
await web3.sendAndConfirmTransaction(connection, transaction, [fromWallet]);
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"),
})
);
🛠 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,
})
);
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)
);
🧰 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.
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
November 28, 2024
November 21, 2024