Skip to content

Commit

Permalink
improve examples (#36)
Browse files Browse the repository at this point in the history
* refactor: renamed dir

* refactor: renamed file

* docs: comment

* chore: add web3js v2 for comparison

* feat: comparison

* docs: add readme

* docs: updates

* docs: updates
  • Loading branch information
nickfrosty authored Feb 17, 2025
1 parent a1e342a commit e04ce73
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 23 deletions.
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,9 @@ const transaction = createTransaction({
If your transaction already has the latest blockhash lifetime set via `createTransaction`:

```typescript
import {
signTransactionMessageWithSigners,
setTransactionMessageLifetimeUsingBlockhash,
} from "gill";
import { createTransaction, signTransactionMessageWithSigners } from "gill";

const transaction = createTransaction(...);

const signedTransaction = await signTransactionMessageWithSigners(transaction);
```
Expand All @@ -213,14 +212,19 @@ must set the latest blockhash lifetime before (or during) the signing operation:

```typescript
import {
createTransaction,
createSolanaClient,
signTransactionMessageWithSigners,
setTransactionMessageLifetimeUsingBlockhash,
} from "gill";

const { rpc } = createSolanaClient(...);
const transaction = createTransaction(...);

const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

const signedTransaction = await signTransactionMessageWithSigners(
setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, transaction),
);
```

Expand All @@ -230,9 +234,9 @@ To send and confirm a transaction to the blockchain, you can use the `sendAndCon
function initialized from `createSolanaClient`.

```typescript
import { createSolanaClient, createTransaction, signTransactionMessageWithSigners } from "gill";
import { ... } from "gill";

const { rpc, rpcSubscriptions, sendAndConfirmTransaction } = createSolanaClient({
const { sendAndConfirmTransaction } = createSolanaClient({
urlOrMoniker: "mainnet",
});

Expand All @@ -241,6 +245,8 @@ const transaction = createTransaction(...);
const signedTransaction = await signTransactionMessageWithSigners(transaction);
const signature: string = getSignatureFromTransaction(signedTransaction);

console.log(getExplorerLink({ transaction: signature }));

// default commitment level of `confirmed`
await sendAndConfirmTransaction(signedTransaction)
```
Expand Down Expand Up @@ -360,13 +366,19 @@ const rent: bigint = getMinimumBalanceForRentExemption();

// same as
// getMinimumBalanceForRentExemption(0);

// same as, but this requires a network call
// const rent = await rpc.getMinimumBalanceForRentExemption(0n).send();
```

```typescript
import { getMinimumBalanceForRentExemption } from "gill";

const rent: bigint = getMinimumBalanceForRentExemption(50 /* 50 bytes */);
// Expected value: 1_238_880n

// same as, but this requires a network call
// const rent = await rpc.getMinimumBalanceForRentExemption(50n).send();
```

> Note: At this time, the minimum rent amount for an account is calculated based on static values in
Expand Down
File renamed without changes.
11 changes: 11 additions & 0 deletions examples/get-started/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"tabWidth": 2,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": true,
"semi": true,
"trailingComma": "all",
"proseWrap": "always",
"arrowParens": "always",
"printWidth": 80
}
104 changes: 104 additions & 0 deletions examples/get-started/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# gill examples

Gill is aimed at abstracting away many of the complexities and boilerplate
required to perform common interactions with the Solana blockchain, while still
offering the low level "escape hatches" when developers need (or want)
fine-grain control.

Take a look through these examples to see how gill works and even
[how it compares](#comparison-of-gill-vs-web3js-v2) to using the vanilla web3js
v2 library.

## Tech stack used

- TypeScript and NodeJS
- Package manger: `pnpm`
- Running the scripts: `esrun`

## Setup locally

1. Clone this repo to your local system
2. Install the packages via `pnpm install`
3. Change into this directory: `cd examples/get-started`

### Running the included scripts with esrun

Once setup locally, you will be able to run the scripts included within this
repo using `esrun`:

```shell
npx esrun ./src/<script>
pnpx esrun ./src/<script>
```

> From the [esrun](https://www.npmjs.com/package/esrun) readme:
>
> esrun is a "work out of the box" library to execute Typescript (as well as
> modern Javascript with decorators and stuff) without having to use a bundler.
> This is useful for quick demonstrations or when launching your tests written
> in Typescript.
## Recommended flow to explore this repo

After getting setup locally, we recommend exploring the code of the following
files (in order):

- [`intro.ts`](./src/intro.ts)
- [`tokens.ts`](./src/tokens.ts)

#### `intro.ts`

A brief introduction to the `gill` library. Demonstrating and explaining the
commonly used tasks involved to interact with the Solana blockchain, including:

- load a keypair signer from the local filesystem
- create an rpc connection to the blockchain
- creating basic instructions (like the memo instruction)
- getting the latest blockhash
- building a complete transaction
- signing the transaction with the loaded local keypair signer
- getting the signature of a transaction (even before it is sent)
- logging Solana Explorer links
- sending and confirming a transaction

These are all the most basic tasks required for any application sending
transaction to the Solana blockchain.

#### `tokens.ts`

Demonstrating how to use gill's "transaction builders" to create a brand new
Solana token (with onchain metadata) and then mint tokens to another user's
wallet:

- load a keypair signer from the local filesystem
- create an rpc connection to the blockchain
- getting the latest blockhash
- build an optimized transaction to create a token
- sign, send, and confirm that "create token" transaction
- build an optimized transaction to mint
- sign, send, and confirm that "mint tokens" transaction

#### `2.complexTransaction.ts`

An introduction to more complex transactions using Solana web3.js. Demonstrates
how to build a more complex transaction, with multiple instructions.

## Comparison of gill vs web3js v2

You can find comparison scripts that demonstrates some of the differences
between [gill](https://github.com/solana-foundation/gill) and
[web3.js v2](https://github.com/anza-xyz/solana-web3.js).

Both scripts accomplish the same task: send an optimized transaction to the
Solana blockchain.

- Using gill - [`basic.ts`](./src/basic.ts)
- Using web3js v2 - [`basic-compare.ts`](./src/basic-compare.ts)

Both will load a keypair file from your local filesystem (the one used by the
Solana CLI).

Both are written with honest intentions, best practices, and attempt to be as
concise as possible in accomplishing the same task.

You decide which you prefer :)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "gill-examples-esrun",
"name": "gill-examples-basic",
"private": true,
"version": "0.1.0",
"type": "module",
Expand All @@ -10,8 +10,13 @@
"author": "",
"license": "MIT",
"dependencies": {
"gill": "workspace:*",
"dotenv": "^16.4.5"
"@solana-program/compute-budget": "^0.6.1",
"@solana-program/memo": "^0.6.1",
"@solana/web3.js": "2.0.0",
"fastestsmallesttextencoderdecoder": "^1.0.22",
"dotenv": "^16.4.5",
"ws": "^8.18.0",
"gill": "workspace:*"
},
"devDependencies": {
"@types/node": "^22.9.0",
Expand Down
81 changes: 81 additions & 0 deletions examples/get-started/src/basic-compare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { readFileSync } from "node:fs";
import { homedir } from "node:os";
import { resolve } from "node:path";
import {
pipe,
devnet,
createSolanaRpc,
createKeyPairFromBytes,
createSignerFromKeyPair,
createTransactionMessage,
getSignatureFromTransaction,
createSolanaRpcSubscriptions,
sendAndConfirmTransactionFactory,
signTransactionMessageWithSigners,
setTransactionMessageFeePayerSigner,
appendTransactionMessageInstructions,
setTransactionMessageLifetimeUsingBlockhash,
} from "@solana/web3.js";
import { getAddMemoInstruction } from "@solana-program/memo";
import {
getSetComputeUnitLimitInstruction,
getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";

const rpc = createSolanaRpc(devnet("https://api.devnet.solana.com"));

const rpcSubscriptions = createSolanaRpcSubscriptions(
devnet("wss://api.devnet.solana.com"),
);

const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({
rpc,
rpcSubscriptions,
});

const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

const keypairFilePath = "~/.config/solana/id.json";

const resolvedKeypairPath = resolve(keypairFilePath.replace("~", homedir()));

const keypair = await createKeyPairFromBytes(
Uint8Array.from(JSON.parse(readFileSync(resolvedKeypairPath, "utf8"))),
);

const signer = await createSignerFromKeyPair(keypair);

const tx = pipe(
createTransactionMessage({ version: "legacy" }),
(tx) => setTransactionMessageFeePayerSigner(signer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) =>
appendTransactionMessageInstructions(
[
getAddMemoInstruction({
memo: "gm world!",
}),
getSetComputeUnitLimitInstruction({ units: 5000 }),
getSetComputeUnitPriceInstruction({ microLamports: 1000 }),
],
tx,
),
);

const signedTransaction = await signTransactionMessageWithSigners(tx);

try {
console.log(
"Sending transaction:",
`https://explorer.solana.com/tx/${getSignatureFromTransaction(signedTransaction)}?cluster=devnet`,
);

await sendAndConfirmTransaction(signedTransaction, {
commitment: "confirmed",
});

console.log("Transaction confirmed!");
} catch (err) {
console.error("Unable to send and confirm the transaction");
console.error(err);
}
49 changes: 49 additions & 0 deletions examples/get-started/src/basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
getExplorerLink,
createTransaction,
createSolanaClient,
getSignatureFromTransaction,
signTransactionMessageWithSigners,
} from "gill";
import { loadKeypairSignerFromFile } from "gill/node";
import { getAddMemoInstruction } from "gill/programs";

const { rpc, sendAndConfirmTransaction } = createSolanaClient({
urlOrMoniker: "devnet",
});

const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

const signer = await loadKeypairSignerFromFile();

const tx = createTransaction({
version: "legacy",
feePayer: signer,
instructions: [
getAddMemoInstruction({
memo: "gm world!",
}),
],
latestBlockhash,
computeUnitLimit: 5000,
computeUnitPrice: 1000,
});

const signedTransaction = await signTransactionMessageWithSigners(tx);

try {
console.log(
"Sending transaction:",
getExplorerLink({
cluster: "devnet",
transaction: getSignatureFromTransaction(signedTransaction),
}),
);

await sendAndConfirmTransaction(signedTransaction);

console.log("Transaction confirmed!");
} catch (err) {
console.error("Unable to send and confirm the transaction");
console.error(err);
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ try {
*/
await sendAndConfirmTransaction(signedTransaction);

// you can also manually define additional settings for sending your transaction
// await sendAndConfirmTransaction(signedTransaction, {
// commitment: "confirmed",
// skipPreflight: true,
Expand Down
Loading

0 comments on commit e04ce73

Please sign in to comment.