docs: updated absolute routes to local routes

This commit is contained in:
nickfrosty 2022-08-08 16:37:58 -04:00 committed by Jacob Creech
parent 555db7e416
commit c7a997872b
6 changed files with 292 additions and 239 deletions

View File

@ -4,19 +4,19 @@ title: Web3 JavaScript API
## What is Solana-Web3.js?
The Solana-Web3.js library aims to provide complete coverage of Solana. The library was built on top of the [Solana JSON RPC API](https://docs.solana.com/developing/clients/jsonrpc-api).
The Solana-Web3.js library aims to provide complete coverage of Solana. The library was built on top of the [Solana JSON RPC API](../clients/jsonrpc-api.md).
You can find the full documentation for the `@solana/web3.js` library [here](https://solana-labs.github.io/solana-web3.js/).
## Common Terminology
| Term | Definition |
|-------------|------------------------|
| Program | Stateless executable code written to interpret instructions. Programs are capable of performing actions based on the instructions provided. |
| Term | Definition |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Program | Stateless executable code written to interpret instructions. Programs are capable of performing actions based on the instructions provided. |
| Instruction | The smallest unit of a program that a client can include in a transaction. Within its processing code, an instruction may contain one or more cross-program invocations. |
| Transaction | One or more instructions signed by the client using one or more Keypairs and executed atomically with only two possible outcomes: success or failure. |
| Transaction | One or more instructions signed by the client using one or more Keypairs and executed atomically with only two possible outcomes: success or failure. |
For the full list of terms, see [Solana terminology](https://docs.solana.com/terminology#cross-program-invocation)
For the full list of terms, see [Solana terminology](../../terminology#cross-program-invocation)
## Getting Started
@ -49,19 +49,17 @@ $ npm install --save @solana/web3.js
#### Javascript
```javascript
const solanaWeb3 = require('@solana/web3.js');
const solanaWeb3 = require("@solana/web3.js");
console.log(solanaWeb3);
```
#### ES6
```javascript
import * as solanaWeb3 from '@solana/web3.js';
import * as solanaWeb3 from "@solana/web3.js";
console.log(solanaWeb3);
```
#### Browser Bundle
```javascript
@ -76,13 +74,14 @@ console.log(solanaWeb3);
To allow users to use your dApp or application on Solana, they will need to get access to their Keypair. A Keypair is a private key with a matching public key, used to sign transactions.
There are two ways to obtain a Keypair:
1. Generate a new Keypair
2. Obtain a Keypair using the secret key
You can obtain a new Keypair with the following:
```javascript
const {Keypair} = require("@solana/web3.js");
const { Keypair } = require("@solana/web3.js");
let keypair = Keypair.generate();
```
@ -92,15 +91,13 @@ This will generate a brand new Keypair for a user to fund and use within your ap
You can allow entry of the secretKey using a textbox, and obtain the Keypair with `Keypair.fromSecretKey(secretKey)`.
```javascript
const {Keypair} = require("@solana/web3.js");
const { Keypair } = require("@solana/web3.js");
let secretKey = Uint8Array.from([
202, 171, 192, 129, 150, 189, 204, 241, 142, 71, 205,
2, 81, 97, 2, 176, 48, 81, 45, 1, 96, 138,
220, 132, 231, 131, 120, 77, 66, 40, 97, 172, 91,
245, 84, 221, 157, 190, 9, 145, 176, 130, 25, 43,
72, 107, 190, 229, 75, 88, 191, 136, 7, 167, 109,
91, 170, 164, 186, 15, 142, 36, 12, 23
202, 171, 192, 129, 150, 189, 204, 241, 142, 71, 205, 2, 81, 97, 2, 176, 48,
81, 45, 1, 96, 138, 220, 132, 231, 131, 120, 77, 66, 40, 97, 172, 91, 245, 84,
221, 157, 190, 9, 145, 176, 130, 25, 43, 72, 107, 190, 229, 75, 88, 191, 136,
7, 167, 109, 91, 170, 164, 186, 15, 142, 36, 12, 23,
]);
let keypair = Keypair.fromSecretKey(secretKey);
@ -117,7 +114,12 @@ A transaction in Solana-Web3.js is created using the [`Transaction`](javascript-
Take the example of a transfer transaction:
```javascript
const {Keypair, Transaction, SystemProgram, LAMPORTS_PER_SOL} = require("@solana/web3.js");
const {
Keypair,
Transaction,
SystemProgram,
LAMPORTS_PER_SOL,
} = require("@solana/web3.js");
let fromKeypair = Keypair.generate();
let toKeypair = Keypair.generate();
@ -127,8 +129,8 @@ transaction.add(
SystemProgram.transfer({
fromPubkey: fromKeypair.publicKey,
toPubkey: toKeypair.publicKey,
lamports: LAMPORTS_PER_SOL
})
lamports: LAMPORTS_PER_SOL,
}),
);
```
@ -137,16 +139,16 @@ The above code achieves creating a transaction ready to be signed and broadcaste
All that is left is to sign the transaction with keypair and send it over the network. You can accomplish sending a transaction by using `sendAndConfirmTransaction` if you wish to alert the user or do something after a transaction is finished, or use `sendTransaction` if you don't need to wait for the transaction to be confirmed.
```javascript
const {sendAndConfirmTransaction, clusterApiUrl, Connection} = require("@solana/web3.js");
const {
sendAndConfirmTransaction,
clusterApiUrl,
Connection,
} = require("@solana/web3.js");
let keypair = Keypair.generate();
let connection = new Connection(clusterApiUrl('testnet'));
let connection = new Connection(clusterApiUrl("testnet"));
sendAndConfirmTransaction(
connection,
transaction,
[keypair]
);
sendAndConfirmTransaction(connection, transaction, [keypair]);
```
The above code takes in a `TransactionInstruction` using `SystemProgram`, creates a `Transaction`, and sends it over the network. You use `Connection` in order to define which Solana network you are connecting to, namely `mainnet-beta`, `testnet`, or `devnet`.
@ -175,7 +177,7 @@ Let's look at how to call this instruction using solana-web3.js:
```javascript
let keypair = web3.Keypair.generate();
let payer = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl('testnet'));
let connection = new web3.Connection(web3.clusterApiUrl("testnet"));
let airdropSignature = await connection.requestAirdrop(
payer.publicKey,
@ -189,9 +191,9 @@ First, we set up the account Keypair and connection so that we have an account t
```javascript
let allocateTransaction = new web3.Transaction({
feePayer: payer.publicKey
});
let keys = [{pubkey: keypair.publicKey, isSigner: true, isWritable: true}];
feePayer: payer.publicKey,
});
let keys = [{ pubkey: keypair.publicKey, isSigner: true, isWritable: true }];
let params = { space: 100 };
```
@ -200,10 +202,7 @@ We create the transaction `allocateTransaction`, keys, and params objects. `feeP
```javascript
let allocateStruct = {
index: 8,
layout: struct([
u32('instruction'),
ns64('space'),
])
layout: struct([u32("instruction"), ns64("space")]),
};
```
@ -270,20 +269,25 @@ The `layout` in the allocate struct must always have `u32('instruction')` first
```javascript
let data = Buffer.alloc(allocateStruct.layout.span);
let layoutFields = Object.assign({instruction: allocateStruct.index}, params);
let layoutFields = Object.assign({ instruction: allocateStruct.index }, params);
allocateStruct.layout.encode(layoutFields, data);
```
Using the previously created bufferLayout, we can allocate a data buffer. We then assign our params `{ space: 100 }` so that it maps correctly to the layout, and encode it to the data buffer. Now the data is ready to be sent to the program.
```javascript
allocateTransaction.add(new web3.TransactionInstruction({
keys,
programId: web3.SystemProgram.programId,
data,
}));
allocateTransaction.add(
new web3.TransactionInstruction({
keys,
programId: web3.SystemProgram.programId,
data,
}),
);
await web3.sendAndConfirmTransaction(connection, allocateTransaction, [payer, keypair]);
await web3.sendAndConfirmTransaction(connection, allocateTransaction, [
payer,
keypair,
]);
```
Finally, we add the transaction instruction with all the account keys, payer, data, and programId and broadcast the transaction to the network.
@ -291,14 +295,14 @@ Finally, we add the transaction instruction with all the account keys, payer, da
The full code can be found below.
```javascript
const {struct, u32, ns64} = require("@solana/buffer-layout");
const {Buffer} = require('buffer');
const { struct, u32, ns64 } = require("@solana/buffer-layout");
const { Buffer } = require("buffer");
const web3 = require("@solana/web3.js");
let keypair = web3.Keypair.generate();
let payer = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl('testnet'));
let connection = new web3.Connection(web3.clusterApiUrl("testnet"));
let airdropSignature = await connection.requestAirdrop(
payer.publicKey,
@ -308,28 +312,30 @@ let airdropSignature = await connection.requestAirdrop(
await connection.confirmTransaction(airdropSignature);
let allocateTransaction = new web3.Transaction({
feePayer: payer.publicKey
feePayer: payer.publicKey,
});
let keys = [{pubkey: keypair.publicKey, isSigner: true, isWritable: true}];
let keys = [{ pubkey: keypair.publicKey, isSigner: true, isWritable: true }];
let params = { space: 100 };
let allocateStruct = {
index: 8,
layout: struct([
u32('instruction'),
ns64('space'),
])
layout: struct([u32("instruction"), ns64("space")]),
};
let data = Buffer.alloc(allocateStruct.layout.span);
let layoutFields = Object.assign({instruction: allocateStruct.index}, params);
let layoutFields = Object.assign({ instruction: allocateStruct.index }, params);
allocateStruct.layout.encode(layoutFields, data);
allocateTransaction.add(new web3.TransactionInstruction({
keys,
programId: web3.SystemProgram.programId,
data,
}));
allocateTransaction.add(
new web3.TransactionInstruction({
keys,
programId: web3.SystemProgram.programId,
data,
}),
);
await web3.sendAndConfirmTransaction(connection, allocateTransaction, [payer, keypair]);
await web3.sendAndConfirmTransaction(connection, allocateTransaction, [
payer,
keypair,
]);
```

View File

@ -4,7 +4,7 @@ title: Web3 API Reference
## Web3 API Reference Guide
The `@solana/web3.js` library is a package that has coverage over the [Solana JSON RPC API](https://docs.solana.com/developing/clients/jsonrpc-api).
The `@solana/web3.js` library is a package that has coverage over the [Solana JSON RPC API](../clients/jsonrpc-api.md).
You can find the full documentation for the `@solana/web3.js` library [here](https://solana-labs.github.io/solana-web3.js/).
@ -14,7 +14,7 @@ You can find the full documentation for the `@solana/web3.js` library [here](htt
[Source Documentation](https://solana-labs.github.io/solana-web3.js/classes/Connection.html)
Connection is used to interact with the [Solana JSON RPC](https://docs.solana.com/developing/clients/jsonrpc-api). You can use Connection to confirm transactions, get account info, and more.
Connection is used to interact with the [Solana JSON RPC](../clients/jsonrpc-api.md). You can use Connection to confirm transactions, get account info, and more.
You create a connection by defining the JSON RPC cluster endpoint and the desired commitment. Once this is complete, you can use this connection object to interact with any of the Solana JSON RPC API.
@ -23,7 +23,7 @@ You create a connection by defining the JSON RPC cluster endpoint and the desire
```javascript
const web3 = require("@solana/web3.js");
let connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");
let slot = await connection.getSlot();
console.log(slot);
@ -64,16 +64,16 @@ A transaction is used to interact with programs on the Solana blockchain. These
#### Example Usage
```javascript
const web3 = require('@solana/web3.js');
const nacl = require('tweetnacl');
const web3 = require("@solana/web3.js");
const nacl = require("tweetnacl");
// Airdrop SOL for paying transactions
let payer = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");
let airdropSignature = await connection.requestAirdrop(
payer.publicKey,
web3.LAMPORTS_PER_SOL,
payer.publicKey,
web3.LAMPORTS_PER_SOL,
);
await connection.confirmTransaction(airdropSignature);
@ -84,27 +84,31 @@ let toAccount = web3.Keypair.generate();
let transaction = new web3.Transaction();
// Add an instruction to execute
transaction.add(web3.SystemProgram.transfer({
transaction.add(
web3.SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: toAccount.publicKey,
lamports: 1000,
}));
}),
);
// Send and confirm transaction
// Note: feePayer is by default the first signer, or payer, if the parameter is not set
await web3.sendAndConfirmTransaction(connection, transaction, [payer])
await web3.sendAndConfirmTransaction(connection, transaction, [payer]);
// Alternatively, manually construct the transaction
let recentBlockhash = await connection.getRecentBlockhash();
let manualTransaction = new web3.Transaction({
recentBlockhash: recentBlockhash.blockhash,
feePayer: payer.publicKey
recentBlockhash: recentBlockhash.blockhash,
feePayer: payer.publicKey,
});
manualTransaction.add(web3.SystemProgram.transfer({
manualTransaction.add(
web3.SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: toAccount.publicKey,
lamports: 1000,
}));
}),
);
let transactionBuffer = manualTransaction.serializeMessage();
let signature = nacl.sign.detached(transactionBuffer, payer.secretKey);
@ -112,7 +116,7 @@ let signature = nacl.sign.detached(transactionBuffer, payer.secretKey);
manualTransaction.addSignature(payer.publicKey, signature);
let isVerifiedSignature = manualTransaction.verifySignatures();
console.log(`The signatures were verifed: ${isVerifiedSignature}`)
console.log(`The signatures were verifed: ${isVerifiedSignature}`);
// The signatures were verified: true
@ -130,7 +134,7 @@ The keypair is used to create an account with a public key and secret key within
#### Example Usage
```javascript
const {Keypair} = require("@solana/web3.js")
const { Keypair } = require("@solana/web3.js");
let account = Keypair.generate();
@ -147,8 +151,10 @@ console.log(account.secretKey);
// 205, 189, 165, 112, 32, 200, 116, 164, 234
// ]
let seed = Uint8Array.from([70,60,102,100,70,60,102,100,70,60,102,100,70,60,102,100,70,60,102,100,70,60,102,100,70,60,102,100,70,60,102,100]);
let seed = Uint8Array.from([
70, 60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100, 70,
60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100,
]);
let accountFromSeed = Keypair.fromSeed(seed);
console.log(accountFromSeed.publicKey.toBase58());
@ -164,7 +170,6 @@ console.log(accountFromSeed.secretKey);
// 227, 60, 72, 215, 47, 208, 209, 162, 59
// ]
let accountFromSecret = Keypair.fromSecretKey(account.secretKey);
console.log(accountFromSecret.publicKey.toBase58());
@ -196,25 +201,33 @@ A PublicKey can be created with a base58 encoded string, buffer, Uint8Array, num
#### Example Usage
```javascript
const {Buffer} = require('buffer');
const web3 = require('@solana/web3.js');
const crypto = require('crypto');
const { Buffer } = require("buffer");
const web3 = require("@solana/web3.js");
const crypto = require("crypto");
// Create a PublicKey with a base58 encoded string
let base58publicKey = new web3.PublicKey('5xot9PVkphiX2adznghwrAuxGs2zeWisNSxMW6hU6Hkj');
let base58publicKey = new web3.PublicKey(
"5xot9PVkphiX2adznghwrAuxGs2zeWisNSxMW6hU6Hkj",
);
console.log(base58publicKey.toBase58());
// 5xot9PVkphiX2adznghwrAuxGs2zeWisNSxMW6hU6Hkj
// Create a Program Address
let highEntropyBuffer = crypto.randomBytes(31);
let programAddressFromKey = await web3.PublicKey.createProgramAddress([highEntropyBuffer.slice(0, 31)], base58publicKey);
let programAddressFromKey = await web3.PublicKey.createProgramAddress(
[highEntropyBuffer.slice(0, 31)],
base58publicKey,
);
console.log(`Generated Program Address: ${programAddressFromKey.toBase58()}`);
// Generated Program Address: 3thxPEEz4EDWHNxo1LpEpsAxZryPAHyvNVXJEJWgBgwJ
// Find Program address given a PublicKey
let validProgramAddress = await web3.PublicKey.findProgramAddress([Buffer.from('', 'utf8')], programAddressFromKey);
let validProgramAddress = await web3.PublicKey.findProgramAddress(
[Buffer.from("", "utf8")],
programAddressFromKey,
);
console.log(`Valid Program Address: ${validProgramAddress}`);
// Valid Program Address: C14Gs3oyeXbASzwUpqSymCKpEyccfEuSe8VRar9vJQRE,253
@ -233,11 +246,11 @@ const web3 = require("@solana/web3.js");
// Airdrop SOL for paying transactions
let payer = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");
let airdropSignature = await connection.requestAirdrop(
payer.publicKey,
web3.LAMPORTS_PER_SOL,
payer.publicKey,
web3.LAMPORTS_PER_SOL,
);
await connection.confirmTransaction(airdropSignature);
@ -245,63 +258,74 @@ await connection.confirmTransaction(airdropSignature);
// Allocate Account Data
let allocatedAccount = web3.Keypair.generate();
let allocateInstruction = web3.SystemProgram.allocate({
accountPubkey: allocatedAccount.publicKey,
space: 100,
})
accountPubkey: allocatedAccount.publicKey,
space: 100,
});
let transaction = new web3.Transaction().add(allocateInstruction);
await web3.sendAndConfirmTransaction(connection, transaction, [payer, allocatedAccount])
await web3.sendAndConfirmTransaction(connection, transaction, [
payer,
allocatedAccount,
]);
// Create Nonce Account
let nonceAccount = web3.Keypair.generate();
let minimumAmountForNonceAccount = await connection.getMinimumBalanceForRentExemption(
web3.NONCE_ACCOUNT_LENGTH,
);
let minimumAmountForNonceAccount =
await connection.getMinimumBalanceForRentExemption(web3.NONCE_ACCOUNT_LENGTH);
let createNonceAccountTransaction = new web3.Transaction().add(
web3.SystemProgram.createNonceAccount({
web3.SystemProgram.createNonceAccount({
fromPubkey: payer.publicKey,
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: payer.publicKey,
lamports: minimumAmountForNonceAccount,
}),
}),
);
await web3.sendAndConfirmTransaction(connection, createNonceAccountTransaction, [payer, nonceAccount])
await web3.sendAndConfirmTransaction(
connection,
createNonceAccountTransaction,
[payer, nonceAccount],
);
// Advance nonce - Used to create transactions as an account custodian
let advanceNonceTransaction = new web3.Transaction().add(
web3.SystemProgram.nonceAdvance({
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: payer.publicKey,
}),
web3.SystemProgram.nonceAdvance({
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: payer.publicKey,
}),
);
await web3.sendAndConfirmTransaction(connection, advanceNonceTransaction, [payer])
await web3.sendAndConfirmTransaction(connection, advanceNonceTransaction, [
payer,
]);
// Transfer lamports between accounts
let toAccount = web3.Keypair.generate();
let transferTransaction = new web3.Transaction().add(
web3.SystemProgram.transfer({
web3.SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: toAccount.publicKey,
lamports: 1000,
}),
}),
);
await web3.sendAndConfirmTransaction(connection, transferTransaction, [payer])
await web3.sendAndConfirmTransaction(connection, transferTransaction, [payer]);
// Assign a new account to a program
let programId = web3.Keypair.generate();
let assignedAccount = web3.Keypair.generate();
let assignTransaction = new web3.Transaction().add(
web3.SystemProgram.assign({
web3.SystemProgram.assign({
accountPubkey: assignedAccount.publicKey,
programId: programId.publicKey,
}),
}),
);
await web3.sendAndConfirmTransaction(connection, assignTransaction, [payer, assignedAccount]);
await web3.sendAndConfirmTransaction(connection, assignTransaction, [
payer,
assignedAccount,
]);
```
### Secp256k1Program
@ -313,49 +337,52 @@ The Secp256k1Program is used to verify Secp256k1 signatures, which are used by b
#### Example Usage
```javascript
const {keccak_256} = require('js-sha3');
const { keccak_256 } = require("js-sha3");
const web3 = require("@solana/web3.js");
const secp256k1 = require('secp256k1');
const secp256k1 = require("secp256k1");
// Create a Ethereum Address from secp256k1
let secp256k1PrivateKey;
do {
secp256k1PrivateKey = web3.Keypair.generate().secretKey.slice(0, 32);
secp256k1PrivateKey = web3.Keypair.generate().secretKey.slice(0, 32);
} while (!secp256k1.privateKeyVerify(secp256k1PrivateKey));
let secp256k1PublicKey = secp256k1.publicKeyCreate(secp256k1PrivateKey, false).slice(1);
let secp256k1PublicKey = secp256k1
.publicKeyCreate(secp256k1PrivateKey, false)
.slice(1);
let ethAddress = web3.Secp256k1Program.publicKeyToEthAddress(secp256k1PublicKey);
console.log(`Ethereum Address: 0x${ethAddress.toString('hex')}`);
let ethAddress =
web3.Secp256k1Program.publicKeyToEthAddress(secp256k1PublicKey);
console.log(`Ethereum Address: 0x${ethAddress.toString("hex")}`);
// Ethereum Address: 0xadbf43eec40694eacf36e34bb5337fba6a2aa8ee
// Fund a keypair to create instructions
let fromPublicKey = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");
let airdropSignature = await connection.requestAirdrop(
fromPublicKey.publicKey,
web3.LAMPORTS_PER_SOL,
fromPublicKey.publicKey,
web3.LAMPORTS_PER_SOL,
);
await connection.confirmTransaction(airdropSignature);
// Sign Message with Ethereum Key
let plaintext = Buffer.from('string address');
let plaintext = Buffer.from("string address");
let plaintextHash = Buffer.from(keccak_256.update(plaintext).digest());
let {signature, recid: recoveryId} = secp256k1.ecdsaSign(
plaintextHash,
secp256k1PrivateKey
let { signature, recid: recoveryId } = secp256k1.ecdsaSign(
plaintextHash,
secp256k1PrivateKey,
);
// Create transaction to verify the signature
let transaction = new Transaction().add(
web3.Secp256k1Program.createInstructionWithEthAddress({
ethAddress: ethAddress.toString('hex'),
plaintext,
signature,
recoveryId,
}),
web3.Secp256k1Program.createInstructionWithEthAddress({
ethAddress: ethAddress.toString("hex"),
plaintext,
signature,
recoveryId,
}),
);
// Transaction will succeed if the message is verified to be signed by the address
@ -371,61 +398,57 @@ Message is used as another way to construct transactions. You can construct a me
#### Example Usage
```javascript
const {Buffer} = require("buffer");
const bs58 = require('bs58');
const web3 = require('@solana/web3.js');
const { Buffer } = require("buffer");
const bs58 = require("bs58");
const web3 = require("@solana/web3.js");
let toPublicKey = web3.Keypair.generate().publicKey;
let fromPublicKey = web3.Keypair.generate();
let connection = new web3.Connection(
web3.clusterApiUrl('devnet'),
'confirmed'
);
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");
let airdropSignature = await connection.requestAirdrop(
fromPublicKey.publicKey,
web3.LAMPORTS_PER_SOL,
fromPublicKey.publicKey,
web3.LAMPORTS_PER_SOL,
);
await connection.confirmTransaction(airdropSignature);
let type = web3.SYSTEM_INSTRUCTION_LAYOUTS.Transfer;
let data = Buffer.alloc(type.layout.span);
let layoutFields = Object.assign({instruction: type.index});
let layoutFields = Object.assign({ instruction: type.index });
type.layout.encode(layoutFields, data);
let recentBlockhash = await connection.getRecentBlockhash();
let messageParams = {
accountKeys: [
fromPublicKey.publicKey.toString(),
toPublicKey.toString(),
web3.SystemProgram.programId.toString()
],
header: {
numReadonlySignedAccounts: 0,
numReadonlyUnsignedAccounts: 1,
numRequiredSignatures: 1,
accountKeys: [
fromPublicKey.publicKey.toString(),
toPublicKey.toString(),
web3.SystemProgram.programId.toString(),
],
header: {
numReadonlySignedAccounts: 0,
numReadonlyUnsignedAccounts: 1,
numRequiredSignatures: 1,
},
instructions: [
{
accounts: [0, 1],
data: bs58.encode(data),
programIdIndex: 2,
},
instructions: [
{
accounts: [0, 1],
data: bs58.encode(data),
programIdIndex: 2,
},
],
recentBlockhash,
],
recentBlockhash,
};
let message = new web3.Message(messageParams);
let transaction = web3.Transaction.populate(
message,
[fromPublicKey.publicKey.toString()]
);
let transaction = web3.Transaction.populate(message, [
fromPublicKey.publicKey.toString(),
]);
await web3.sendAndConfirmTransaction(connection, transaction, [fromPublicKey])
await web3.sendAndConfirmTransaction(connection, transaction, [fromPublicKey]);
```
### Struct
@ -437,6 +460,7 @@ The struct class is used to create Rust compatible structs in javascript. This c
#### Example Usage
Struct in Rust:
```rust
pub struct Fee {
pub denominator: u64,
@ -445,9 +469,10 @@ pub struct Fee {
```
Using web3:
```javascript
import BN from 'bn.js';
import {Struct} from '@solana/web3.js';
import BN from "bn.js";
import { Struct } from "@solana/web3.js";
export class Fee extends Struct {
denominator: BN;
@ -464,6 +489,7 @@ The Enum class is used to represent a Rust compatible Enum in javascript. The en
#### Example Usage
Rust:
```rust
pub enum AccountType {
Uninitialized,
@ -473,8 +499,9 @@ pub enum AccountType {
```
Web3:
```javascript
import {Enum} from '@solana/web3.js';
import { Enum } from "@solana/web3.js";
export class AccountType extends Enum {}
```
@ -490,13 +517,10 @@ You can create a nonce account by first creating a normal account, then using `S
#### Example Usage
```javascript
const web3 = require('@solana/web3.js');
const web3 = require("@solana/web3.js");
// Create connection
let connection = new web3.Connection(
web3.clusterApiUrl('devnet'),
'confirmed',
);
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");
// Generate accounts
let account = web3.Keypair.generate();
@ -504,36 +528,35 @@ let nonceAccount = web3.Keypair.generate();
// Fund account
let airdropSignature = await connection.requestAirdrop(
account.publicKey,
web3.LAMPORTS_PER_SOL,
account.publicKey,
web3.LAMPORTS_PER_SOL,
);
await connection.confirmTransaction(airdropSignature);
// Get Minimum amount for rent exemption
let minimumAmount = await connection.getMinimumBalanceForRentExemption(
web3.NONCE_ACCOUNT_LENGTH,
web3.NONCE_ACCOUNT_LENGTH,
);
// Form CreateNonceAccount transaction
let transaction = new web3.Transaction().add(
web3.SystemProgram.createNonceAccount({
web3.SystemProgram.createNonceAccount({
fromPubkey: account.publicKey,
noncePubkey: nonceAccount.publicKey,
authorizedPubkey: account.publicKey,
lamports: minimumAmount,
}),
}),
);
// Create Nonce Account
await web3.sendAndConfirmTransaction(
connection,
transaction,
[account, nonceAccount]
);
await web3.sendAndConfirmTransaction(connection, transaction, [
account,
nonceAccount,
]);
let nonceAccountData = await connection.getNonce(
nonceAccount.publicKey,
'confirmed',
nonceAccount.publicKey,
"confirmed",
);
console.log(nonceAccountData);
@ -546,12 +569,12 @@ console.log(nonceAccountData);
// }
let nonceAccountInfo = await connection.getAccountInfo(
nonceAccount.publicKey,
'confirmed'
nonceAccount.publicKey,
"confirmed",
);
let nonceAccountFromInfo = web3.NonceAccount.fromAccountData(
nonceAccountInfo.data
nonceAccountInfo.data,
);
console.log(nonceAccountFromInfo);
@ -575,10 +598,12 @@ Vote account is an object that grants the capability of decoding vote accounts f
#### Example Usage
```javascript
const web3 = require('@solana/web3.js');
const web3 = require("@solana/web3.js");
let voteAccountInfo = await connection.getProgramAccounts(web3.VOTE_PROGRAM_ID);
let voteAccountFromData = web3.VoteAccount.fromAccountData(voteAccountInfo[0].account.data);
let voteAccountFromData = web3.VoteAccount.fromAccountData(
voteAccountInfo[0].account.data,
);
console.log(voteAccountFromData);
/*
VoteAccount {
@ -650,11 +675,11 @@ const web3 = require("@solana/web3.js");
// Fund a key to create transactions
let fromPublicKey = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");
let airdropSignature = await connection.requestAirdrop(
fromPublicKey.publicKey,
web3.LAMPORTS_PER_SOL,
fromPublicKey.publicKey,
web3.LAMPORTS_PER_SOL,
);
await connection.confirmTransaction(airdropSignature);
@ -663,20 +688,29 @@ let stakeAccount = web3.Keypair.generate();
let authorizedAccount = web3.Keypair.generate();
/* Note: This is the minimum amount for a stake account -- Add additional Lamports for staking
For example, we add 50 lamports as part of the stake */
let lamportsForStakeAccount = (await connection.getMinimumBalanceForRentExemption(web3.StakeProgram.space)) + 50;
let lamportsForStakeAccount =
(await connection.getMinimumBalanceForRentExemption(
web3.StakeProgram.space,
)) + 50;
let createAccountTransaction = web3.StakeProgram.createAccount({
fromPubkey: fromPublicKey.publicKey,
authorized: new web3.Authorized(authorizedAccount.publicKey, authorizedAccount.publicKey),
lamports: lamportsForStakeAccount,
lockup: new web3.Lockup(0, 0, fromPublicKey.publicKey),
stakePubkey: stakeAccount.publicKey
fromPubkey: fromPublicKey.publicKey,
authorized: new web3.Authorized(
authorizedAccount.publicKey,
authorizedAccount.publicKey,
),
lamports: lamportsForStakeAccount,
lockup: new web3.Lockup(0, 0, fromPublicKey.publicKey),
stakePubkey: stakeAccount.publicKey,
});
await web3.sendAndConfirmTransaction(connection, createAccountTransaction, [fromPublicKey, stakeAccount]);
await web3.sendAndConfirmTransaction(connection, createAccountTransaction, [
fromPublicKey,
stakeAccount,
]);
// Check that stake is available
let stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake balance: ${stakeBalance}`)
console.log(`Stake balance: ${stakeBalance}`);
// Stake balance: 2282930
// We can verify the state of our stake. This may take some time to become active
@ -686,35 +720,42 @@ console.log(`Stake state: ${stakeState.state}`);
// To delegate our stake, we get the current vote accounts and choose the first
let voteAccounts = await connection.getVoteAccounts();
let voteAccount = voteAccounts.current.concat(
voteAccounts.delinquent,
)[0];
let voteAccount = voteAccounts.current.concat(voteAccounts.delinquent)[0];
let votePubkey = new web3.PublicKey(voteAccount.votePubkey);
// We can then delegate our stake to the voteAccount
let delegateTransaction = web3.StakeProgram.delegate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: authorizedAccount.publicKey,
votePubkey: votePubkey,
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: authorizedAccount.publicKey,
votePubkey: votePubkey,
});
await web3.sendAndConfirmTransaction(connection, delegateTransaction, [fromPublicKey, authorizedAccount]);
await web3.sendAndConfirmTransaction(connection, delegateTransaction, [
fromPublicKey,
authorizedAccount,
]);
// To withdraw our funds, we first have to deactivate the stake
let deactivateTransaction = web3.StakeProgram.deactivate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: authorizedAccount.publicKey,
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: authorizedAccount.publicKey,
});
await web3.sendAndConfirmTransaction(connection, deactivateTransaction, [fromPublicKey, authorizedAccount]);
await web3.sendAndConfirmTransaction(connection, deactivateTransaction, [
fromPublicKey,
authorizedAccount,
]);
// Once deactivated, we can withdraw our funds
let withdrawTransaction = web3.StakeProgram.withdraw({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: authorizedAccount.publicKey,
toPubkey: fromPublicKey.publicKey,
lamports: stakeBalance,
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: authorizedAccount.publicKey,
toPubkey: fromPublicKey.publicKey,
lamports: stakeBalance,
});
await web3.sendAndConfirmTransaction(connection, withdrawTransaction, [fromPublicKey, authorizedAccount]);
await web3.sendAndConfirmTransaction(connection, withdrawTransaction, [
fromPublicKey,
authorizedAccount,
]);
```
### Authorized
@ -734,7 +775,12 @@ Lockup is used in conjunction with the [StakeProgram](javascript-api.md#StakePro
#### Example Usage
```javascript
const {Authorized, Keypair, Lockup, StakeProgram} = require("@solana/web3.js");
const {
Authorized,
Keypair,
Lockup,
StakeProgram,
} = require("@solana/web3.js");
let account = Keypair.generate();
let stakeAccount = Keypair.generate();
@ -742,13 +788,14 @@ let authorized = new Authorized(account.publicKey, account.publicKey);
let lockup = new Lockup(0, 0, account.publicKey);
let createStakeAccountInstruction = StakeProgram.createAccount({
fromPubkey: account.publicKey,
authorized: authorized,
lamports: 1000,
lockup: lockup,
stakePubkey: stakeAccount.publicKey
fromPubkey: account.publicKey,
authorized: authorized,
lamports: 1000,
lockup: lockup,
stakePubkey: stakeAccount.publicKey,
});
```
The above code creates a `createStakeAccountInstruction` to be used when creating an account with the `StakeProgram`. The Lockup is set to 0 for both the epoch and Unix timestamp, disabling lockup for the account.
See [StakeProgram](javascript-api.md#StakeProgram) for more.

View File

@ -33,8 +33,7 @@ for an example of a C program.
First setup the environment:
- Install the latest Rust stable from https://rustup.rs
- Install the latest Solana command-line tools from
https://docs.solana.com/cli/install-solana-cli-tools
- Install the latest [Solana command-line tools](../../cli/install-solana-cli-tools.md)
Then build using make:

View File

@ -59,8 +59,7 @@ For example:
First setup the environment:
- Install the latest Rust stable from https://rustup.rs/
- Install the latest Solana command-line tools from
https://docs.solana.com/cli/install-solana-cli-tools
- Install the latest [Solana command-line tools](../../cli/install-solana-cli-tools.md)
The normal cargo build is available for building programs against your host
machine which can be used for unit testing:

View File

@ -202,7 +202,7 @@ found in [Accounts](accounts.md#signers)
## Recent Blockhash
A transaction includes a recent [blockhash](terminology.md#blockhash) to prevent
A transaction includes a recent [blockhash](../../terminology.md#blockhash) to prevent
duplication and to give transactions lifetimes. Any transaction that is
completely identical to a previous one is rejected, so adding a newer blockhash
allows multiple transactions to repeat the exact same action. Transactions also

View File

@ -7,7 +7,7 @@ title: Retrying Transactions
On some occasions, a seemingly valid transaction may be dropped before it is
included in a block. This most often occurs during periods of network
congestion, when an RPC node fails to rebroadcast the transaction to the
[leader](https://docs.solana.com/terminology#leader). To an end-user, it may
[leader](../terminology#leader). To an end-user, it may
appear as if their transaction disappears entirely. While RPC nodes are equipped
with a generic rebroadcasting algorithm, application developers are also capable
of developing their own custom rebroadcasting logic.
@ -25,6 +25,7 @@ Fact Sheet
are submitted
- Before re-signing any transaction, it is **very important** to ensure that the
initial transactions blockhash has expired
:::
## The Journey of a Transaction
@ -37,7 +38,7 @@ so that they can be processed into a block. There are two main ways in which a
transaction can be sent to leaders:
1. By proxy via an RPC server and the
[sendTransaction](https://docs.solana.com/developing/clients/jsonrpc-api#sendtransaction)
[sendTransaction](../developing/clients/jsonrpc-api#sendtransaction)
JSON-RPC method
2. Directly to leaders via a
[TPU Client](https://docs.rs/solana-client/1.7.3/solana_client/tpu_client/index.html)
@ -50,9 +51,9 @@ outside of what the client and the relaying RPC nodes are aware of. In the case
of a TPU client, rebroadcast and leader forwarding is handled entirely by the
client software.
![Transaction Journey](/img/rt-tx-journey.png)
![Transaction Journey](../../static/img/rt-tx-journey.png)
<!-- (/img/p_ex_unstaked_dilution.png) -->
<!-- (../../static/img/p_ex_unstaked_dilution.png) -->
### How RPC Nodes Broadcast Transactions
@ -64,7 +65,7 @@ communicate with one another, but does not provide any guarantees regarding
transaction delivery.
Because Solanas leader schedule is known in advance of every
[epoch](https://docs.solana.com/terminology#epoch) (~2 days), an RPC node will
[epoch](../terminology#epoch) (~2 days), an RPC node will
broadcast its transaction directly to the current and next leaders. This is in
contrast to other gossip protocols such as Ethereum that propagate transactions
randomly and broadly across the entire network. By default, RPC nodes will try
@ -89,7 +90,7 @@ The TPU processes transactions in five distinct phases:
- [Proof of History Service](https://github.com/solana-labs/solana/blob/cd6f931223181d5a1d47cba64e857785a175a760/poh/src/poh_service.rs)
- [Broadcast Stage](https://github.com/solana-labs/solana/blob/cd6f931223181d5a1d47cba64e857785a175a760/core/src/tpu.rs#L136)
![TPU Overview](/img/rt-tpu-jito-labs.png)
![TPU Overview](../../static/img/rt-tpu-jito-labs.png)
Of these five phases, the Fetch Stage is responsible for receiving transactions.
Within the Fetch Stage, validators will categorize incoming transactions
@ -132,15 +133,15 @@ it is processed. The first scenario involves transactions that are submitted via
an RPC pool. Occasionally, part of the RPC pool can be sufficiently ahead of the
rest of the pool. This can cause issues when nodes within the pool are required
to work together. In this example, the transactions
[recentBlockhash](https://docs.solana.com/developing/programming-model/transactions#recent-blockhash)
[recentBlockhash](../developing/programming-model/transactions#recent-blockhash)
is queried from the advanced part of the pool (Backend A). When the transaction
is submitted to the lagging part of the pool (Backend B), the nodes will not
recognize the advanced blockhash and will drop the transaction. This can be
detected upon transaction submission if developers enable
[preflight checks](https://docs.solana.com/developing/clients/jsonrpc-api#sendtransaction)
[preflight checks](../developing/clients/jsonrpc-api#sendtransaction)
on `sendTransaction`.
![Dropped via RPC Pool](/img/rt-dropped-via-rpc-pool.png)
![Dropped via RPC Pool](../../static/img/rt-dropped-via-rpc-pool.png)
Temporarily network forks can also result in dropped transactions. If a
validator is slow to replay its blocks within the Banking Stage, it may end up
@ -150,7 +151,7 @@ minority fork. After the transaction is submitted, the cluster can then switch
away from its minority fork before the transaction is processed. In this
scenario, the transaction is dropped due to the blockhash not being found.
![Dropped due to Minority Fork (Before Processed)](/img/rt-dropped-minority-fork-pre-process.png)
![Dropped due to Minority Fork (Before Processed)](../../static/img/rt-dropped-minority-fork-pre-process.png)
### After a transaction is processed and before it is finalized
@ -162,7 +163,7 @@ would fail to reach consensus with the majority of validators that do not
recognize the minority fork. At this time, the transaction would be dropped
before it could be finalized.
![Dropped due to Minority Fork (After Processed)](/img/rt-dropped-minority-fork-post-process.png)
![Dropped due to Minority Fork (After Processed)](../../static/img/rt-dropped-minority-fork-post-process.png)
## Handling Dropped Transactions
@ -189,7 +190,7 @@ the transaction will be processed or finalized by the cluster.
- `skipPreflight`: `boolean` - if true, skip the preflight transaction checks
(default: false)
- (optional) `preflightCommitment`: `string` -
[Commitment](https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment)
[Commitment](../developing/clients/jsonrpc-api#configuring-state-commitment)
level to use for preflight simulations against the bank slot (default:
"finalized").
- (optional) `encoding`: `string` - Encoding used for the transaction data.
@ -203,8 +204,9 @@ Response
- `transaction id`: `string` - First transaction signature embedded in the
transaction, as base-58 encoded string. This transaction id can be used with
[getSignatureStatuses](https://docs.solana.com/developing/clients/jsonrpc-api#getsignaturestatuses)
[getSignatureStatuses](../developing/clients/jsonrpc-api#getsignaturestatuses)
to poll for status updates.
:::
## Customizing Rebroadcast Logic
@ -217,9 +219,9 @@ developers to manually control the retry process
A common pattern for manually retrying transactions involves temporarily storing
the `lastValidBlockHeight` that comes from
[getLatestBlockhash](https://docs.solana.com/developing/clients/jsonrpc-api#getlatestblockhash).
[getLatestBlockhash](../developing/clients/jsonrpc-api#getlatestblockhash).
Once stashed, an application can then
[poll the clusters blockheight](https://docs.solana.com/developing/clients/jsonrpc-api#getblockheight)
[poll the clusters blockheight](../developing/clients/jsonrpc-api#getblockheight)
and manually retry the transaction at an appropriate interval. In times of
network congestion, its advantageous to set `maxRetries` to 0 and manually
rebroadcast via a custom algorithm. While some applications may employ an
@ -287,7 +289,7 @@ const sleep = async (ms: number) => {
When polling via `getLatestBlockhash`, applications should specify their
intended
[commitment](https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment)
[commitment](../developing/clients/jsonrpc-api#configuring-state-commitment)
level. By setting its commitment to `confirmed` (voted on) or `finalized` (~30
blocks after `confirmed`), an application can avoid polling a blockhash from a
minority fork.
@ -329,6 +331,6 @@ In Solana, a dropped transaction can be safely discarded once the blockhash it
references is older than the `lastValidBlockHeight` received from
`getLatestBlockhash`. Developers should keep track of this
`lastValidBlockHeight` by querying
[`getEpochInfo`](https://docs.solana.com/developing/clients/jsonrpc-api#getepochinfo)
[`getEpochInfo`](../developing/clients/jsonrpc-api#getepochinfo)
and comparing with `blockHeight` in the response. Once a blockhash is
invalidated, clients may re-sign with a newly-queried blockhash.