Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions README-en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Solana Web3.js Tutorial

> This tutorial is written by members of the Buff community and is updated weekly with 1-3 sections.

The Solana Web3.js library is a JavaScript-based library for interacting with the Solana blockchain.

This tutorial aims to provide simple examples to help you quickly get started with Solana blockchain development.

---

Before reading, you need to run the following command to install @solana/web3.js. The version used in this tutorial is 1.95.4.

```
$ npm install @solana/[email protected]
```

After that, you can run the code for each section using `npx esrun xxx/index.ts`.

## Table of Contents

0. Basic Terminology

### Basics

1. [Create Wallet & Import Wallet](./en/01-wallet/)
2. [Get SOL Balance of an Account](./en/02-balance/)
3. [Send Your First Transfer Transaction](./en/03-transfer/)
4. [Read Data from the Chain (1): `get` read](./en/04-get/)
5. [Read Data from the Chain (2): `on` subscription](./en/05-on/)
6. [Send Data to the Chain: `send` transaction](./en/06-send/)

### Advanced

7. [Add Priority Fee](./en/07-cu/)
8. [`v0` Transaction](./en/08-v0/)
9. [Parse Buffer](./en/09-buffer/)
10.

### Practical

1. [Listen to Wallet](./en/example-01-subWallet/)
2. [Listen to raydium v4 new liquidity pool creation](./en/example-02-subNewPool/)
3. [Listen to real-time price of raydium clmm token](./en/example-03-subPrice/)
4.

## References

- https://solana-labs.github.io/solana-web3.js/v1.x
- https://solana.com/zh/developers/cookbook
- https://solana.com/docs

## Donation

If you want to support the development of the Buff community, you can donate Solana chain assets to the `buffaAJKmNLao65TDTUGq8oB9HgxkfPLGqPMFQapotJ` address.

Community funds will be used to reward community contributors, including but not limited to `PR`.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Solana Web3.js 库是一个用于与 Solana 区块链进行交互的 JavaScript

本教程旨在提供一些简单的例子,帮助你快速上手 Solana 区块链开发。

> English version (英文版): [README-en.md](./README-en.md)

---

在阅读之前,需要运行如下来安装@solana/web3.js,本教程使用的版本为1.95.4。
Expand Down
68 changes: 68 additions & 0 deletions en/01-wallet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Create Wallet & Import Wallet

> The private key is the only credential for the account; please keep it safe.

This section will introduce how to create your own wallet using the web3.js library.

## Create Wallet

A Solana wallet refers to a pair of `private key` and `public key`, which are the credentials used to access and manage accounts on Solana. The key pair is generated through random numbers to ensure that each key pair is unique.

- Private Key: A confidential key used to prove account ownership. The private key can be used to generate digital signatures and authorize transactions. If the private key is leaked, others can use it to control your account.
- Public Key: The public part paired with the private key. The public key is your account address, and others can send assets to you or query your account balance through the public key, but they cannot use it to authorize operations.

```ts
import { Keypair } from "@solana/web3.js";
import fs from "fs";
import { Buffer } from 'buffer';

// Create wallet
const wallet = Keypair.generate();

// Get public key and private key
const publicKey = wallet.publicKey.toBase58();
const secretKey = wallet.secretKey; // A Uint8Array

// Print
console.log("Wallet Public Key:", publicKey);
console.log("Wallet Private Key:", secretKey);
console.log("Wallet Private Key (base64):", Buffer.from(secretKey).toString("base64"));

// Save Uint8Array private key
fs.writeFileSync("wallet.json", JSON.stringify(Array.from(secretKey)));
```

Run with `npx esrun 01-wallet/index.ts`, the output is as follows:

```bash
Wallet Public Key: EkfAVHeFtDUmGQJH5e67i784wKKNA7jyStKywQWysY73
Wallet Private Key: Uint8Array(64) [
180, 206, 18, 236, 242, 179, 168, 142, 181, 66,
158, 123, 232, 162, 205, 195, 192, 56, 117, 152,
238, 67, 141, 162, 250, 60, 104, 153, 79, 96,
49, 234, 204, 87, 14, 120, 218, 77, 112, 188,
235, 139, 1, 134, 201, 208, 112, 25, 2, 151,
227, 188, 25, 69, 178, 196, 146, 227, 179, 14,
118, 115, 233, 234
]
Wallet Private Key (base64): tM4S7PKzqI61Qp576KLNw8A4dZjuQ42i+jxomU9gMerMVw542k1wvOuLAYbJ0HAZApfjvBlFssSS47MOdnPp6g==
```

The private key is saved in the `wallet.json` file in the root directory of this project. The public key is 32 bytes long, usually encoded in Base58; the private key is 64 bytes long, usually encoded in Base64.

## Import Wallet

Import the private key from the newly saved `wallet.json` file to restore the wallet.

```ts
const secretKey = Uint8Array.from(JSON.parse(fs.readFileSync("wallet.json")));
const wallet = Keypair.fromSecretKey(secretKey);

console.log("Wallet Public Key:", wallet.publicKey.toString());
console.log("Wallet Private Key:", wallet.secretKey);
console.log("Wallet Private Key (base64):", Buffer.from(secretKey).toString("base64"));
```

The output after running should be consistent with the previous output.


26 changes: 26 additions & 0 deletions en/01-wallet/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Keypair } from "@solana/web3.js";
import fs from "fs";
import { Buffer } from 'buffer';

// Create a wallet
const wallet = Keypair.generate();

// Get the public key and secret key
const publicKey = wallet.publicKey.toBase58();
const secretKey = wallet.secretKey; // A Uint8Array

// Print keys
console.log("Wallet Public Key:", publicKey);
console.log("Wallet Secret Key:", secretKey);
console.log("Wallet Secret Key (base64):", Buffer.from(secretKey).toString("base64"));

// Save the Uint8Array secret key
fs.writeFileSync("wallet.json", JSON.stringify(Array.from(secretKey)));

// Import the wallet
// const secretKey = Uint8Array.from(JSON.parse(fs.readFileSync("wallet.json")));
// const wallet = Keypair.fromSecretKey(secretKey);

// console.log("Wallet Public Key:", wallet.publicKey.toString());
// console.log("Wallet Secret Key:", wallet.secretKey);
// console.log("Wallet Secret Key (base64):", Buffer.from(secretKey).toString("base64"));
48 changes: 48 additions & 0 deletions en/02-balance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Get SOL Balance of an Account

> The RPC port is the medium for interacting with the Solana blockchain.

This section will introduce how to create an RPC connection using the `Connection` class and use the `getBalance` method to retrieve the SOL balance of an account.

## Creating an RPC Connection

The `Connection` class is the core class for interacting with the Solana blockchain, providing various methods to communicate with the blockchain. An instance of `Connection` can be created by providing the RPC port and confirmation level, as shown below:

```ts
import { Connection, PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js';

// Create RPC connection
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");
```

`https://api.mainnet-beta.solana.com` is the official RPC port provided by Solana, and `confirmed` is the default confirmation level.

> Note:
> `processed` is a lower confirmation level, meaning the queried data is verified but not fully confirmed. `confirmed` indicates that the node has written the transaction to the blockchain, but it may not be finally confirmed. If a higher confirmation level is needed, `finalized` can be used.

## Querying Account Balance

The `getBalance` method is used to query the SOL balance of a specified account, returning the balance in lamports, which needs to be divided by `LAMPORTS_PER_SOL` to convert to SOL units.

> Note:
> `LAMPORTS_PER_SOL` is the number of lamports in 1 SOL, equal to 10^9.

Here, we will query the SOL balance of Jito1, whose public key is `CXPeim1wQMkcTvEHx9QdhgKREYYJD8bnaCCqPRwJ1to1`.

```ts
async function main() {

// Query Jito1's SOL balance
const publicKey = new PublicKey('CXPeim1wQMkcTvEHx9QdhgKREYYJD8bnaCCqPRwJ1to1');
const balance = await connection.getBalance(publicKey);
console.log(`Jito1 balance: ${balance / LAMPORTS_PER_SOL} SOL`); // Convert to SOL units
}

main();
```

By running the above code with `npx esrun 02-balance/index.ts`, you can see that Jito1's current SOL balance is 9.999906999 SOL.

```
Jito1 balance: 9.999906999 SOL
```
15 changes: 15 additions & 0 deletions en/02-balance/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Connection, PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js';

// Create RPC connection
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");
// const connection = new Connection("https://mainnet-ams.chainbuff.com", "confirmed");

async function main() {

// Query the SOL balance of Jito1
const publicKey = new PublicKey('CXPeim1wQMkcTvEHx9QdhgKREYYJD8bnaCCqPRwJ1to1');
const balance = await connection.getBalance(publicKey);
console.log(`Jito1 balance: ${balance / LAMPORTS_PER_SOL} SOL`); // Convert to SOL unit
}

main();
87 changes: 87 additions & 0 deletions en/03-transfer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Sending Your First Transfer Transaction

> Sending a transaction is the only way to change the on-chain state.

This section will introduce how to create and send your first transfer transaction.

## Creating an RPC Connection and Importing a Wallet

First, as we learned earlier, we need to create an RPC connection and import our wallet private key.

```ts
import {
Connection,
PublicKey,
Keypair,
Transaction,
SystemProgram,
sendAndConfirmTransaction
} from '@solana/web3.js';
import fs from "fs";

// Create RPC connection
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");

// Import wallet locally
const fromSecretKey = Uint8Array.from(JSON.parse(fs.readFileSync("wallet.json")));
const fromWallet = Keypair.fromSecretKey(fromSecretKey);
```

## Creating, Simulating, and Sending a Transfer Transaction

Next, we will create a transaction and add a transfer instruction to `buffaAJKmNLao65TDTUGq8oB9HgxkfPLGqPMFQapotJ`. After that, we can first simulate whether the transaction will succeed. If the simulation is successful, we will actually send the transaction.

> Note:
> `buffaAJKmNLao65TDTUGq8oB9HgxkfPLGqPMFQapotJ` is the public fund account of the Buff community and can be replaced with any other account.

```ts
async function main() {

// Create transaction
const transaction = new Transaction();

// Target address
const toAddress = new PublicKey('buffaAJKmNLao65TDTUGq8oB9HgxkfPLGqPMFQapotJ');

// Add transfer instruction
const instruction = SystemProgram.transfer({
fromPubkey: fromWallet.publicKey,
toPubkey: toAddress,
lamports: 1000, // 1000 lamports
});
transaction.add(instruction);

// Simulate transaction
const simulateResult = await connection.simulateTransaction(transaction, [fromWallet]);
console.log("Simulation result: ", simulateResult);

// Send transaction
const signature = await sendAndConfirmTransaction(connection, transaction, [fromWallet]);
console.log(`Transaction sent, https://solscan.io/tx/${signature}`);
}

main();
```

After running the script with `npx esrun 03-transfer/index.ts`, the output should be as follows:

```bash
Simulation result: {
context: { apiVersion: '2.0.3', slot: 300547622 },
value: {
accounts: null,
err: null,
innerInstructions: null,
logs: [
'Program 11111111111111111111111111111111 invoke [1]',
'Program 11111111111111111111111111111111 success'
],
replacementBlockhash: null,
returnData: null,
unitsConsumed: 150
}
}
Transaction sent: https://solscan.io/tx/3Vfp5qPhF14bNb2jLtTccabCDbHUmxqtXerUvPEjKb6RpJ8jU3H9M9JgcUbDPtgesB3WFP9M8VZTzECgBavnjxaC
```

Through this transaction, we successfully transferred 1000 lamports to `buffaAJKmNLao65TDTUGq8oB9HgxkfPLGqPMFQapotJ`, and you can view this transaction on the blockchain explorer [here](https://solscan.io/tx/3Vfp5qPhF14bNb2jLtTccabCDbHUmxqtXerUvPEjKb6RpJ8jU3H9M9JgcUbDPtgesB3WFP9M8VZTzECgBavnjxaC).
45 changes: 45 additions & 0 deletions en/03-transfer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
Connection,
PublicKey,
Keypair,
Transaction,
SystemProgram,
sendAndConfirmTransaction
} from '@solana/web3.js';
import fs from "fs";

// Create RPC connection
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");
// const connection = new Connection("https://mainnet-ams.chainbuff.com", "confirmed");

// Local import of wallet
const fromSecretKey = Uint8Array.from(JSON.parse(fs.readFileSync("wallet.json")));
// const fromSecretKey = Uint8Array.from(JSON.parse(fs.readFileSync("web3xFMwEPrc92NeeXdAigni95NDnnd2NPuajTirao2.json")));
const fromWallet = Keypair.fromSecretKey(fromSecretKey);

async function main() {

// Create transaction
const transaction = new Transaction();

// Target address
const toAddress = new PublicKey('buffaAJKmNLao65TDTUGq8oB9HgxkfPLGqPMFQapotJ');

// Add transfer instruction
const instruction = SystemProgram.transfer({
fromPubkey: fromWallet.publicKey,
toPubkey: toAddress,
lamports: 1000, // 1000 lamports
});
transaction.add(instruction);

// Simulate transaction
const simulateResult = await connection.simulateTransaction(transaction, [fromWallet]);
console.log("Simulation result: ", simulateResult);

// Send transaction
const signature = await sendAndConfirmTransaction(connection, transaction, [fromWallet]);
console.log(`Transaction sent: https://solscan.io/tx/${signature}`);
}

main();
Loading