Skip to content

Commit

Permalink
feat: add token examples
Browse files Browse the repository at this point in the history
  • Loading branch information
nickfrosty committed Feb 27, 2025
1 parent 7c997f7 commit c79d915
Show file tree
Hide file tree
Showing 13 changed files with 915 additions and 0 deletions.
51 changes: 51 additions & 0 deletions examples/tokens/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.cache
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build
/dist
/bin

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env
!.env.example

# vercel
.vercel

# contentlayer
.contentlayer

# typescript
*.tsbuildinfo
next-env.d.ts

# sitemaps / robots
public/sitemap*
public/robot*

test-ledger
temp

.cache
11 changes: 11 additions & 0 deletions examples/tokens/.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
}
52 changes: 52 additions & 0 deletions examples/tokens/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# gill examples - tokens

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](../get-started/README.md#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/tokens`

### 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):

- [`1.intro.ts`](./src/1.intro.ts)
- [`2.create-token-mint.ts`](./src/2.create-token-mint.ts)
- [`3.create-token-mint-builder.ts`](./src/3.create-token-mint-builder.ts)
- [`4.mint-tokens.ts`](./src/4.mint-tokens.ts)
- [`5.mint-tokens-builder.ts`](./src/5.mint-tokens-builder.ts)
- [`6.transfer-tokens.ts`](./src/6.transfer-tokens.ts)
- [`7.transfer-tokens-builder.ts`](./src/7.transfer-tokens-builder.ts)
20 changes: 20 additions & 0 deletions examples/tokens/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "gill-examples-tokens",
"version": "1.0.0",
"description": "",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "nickfrosty",
"license": "MIT",
"dependencies": {
"dotenv": "^16.4.5",
"esrun": "^3.2.26",
"gill": "workspace:*"
},
"devDependencies": {
"@types/node": "^22.9.0",
"typescript": "^5.6.3"
}
}
103 changes: 103 additions & 0 deletions examples/tokens/src/1.intro.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {
getExplorerLink,
createTransaction,
createSolanaClient,
SolanaClusterMoniker,
getSignatureFromTransaction,
signTransactionMessageWithSigners,
} from "gill";
import { loadKeypairSignerFromFile } from "gill/node";
import { getAddMemoInstruction } from "gill/programs";

/**
* Load a keypair signer from the local filesystem
*
* This defaults to the file path used by the Solana CLI: `~/.config/solana/id.json`
*/
const signer = await loadKeypairSignerFromFile();
console.log("address:", signer.address);

/**
* Declare what Solana network cluster we want our code to interact with
*/
const cluster: SolanaClusterMoniker = "devnet";

/**
* Create a client connection to the Solana blockchain
*
* Note: `urlOrMoniker` can be either a Solana network moniker or a full URL of your RPC provider
*/
const { rpc, sendAndConfirmTransaction } = createSolanaClient({
urlOrMoniker: cluster,
});

/**
* Create a memo instruction to post a simple message onchain
* (the simplest of instruction types!)
*/
const memoIx = getAddMemoInstruction({
memo: "gm world!",
});

/**
* Get the latest blockhash (aka transaction lifetime). This acts as a recent timestamp
* for the blockchain to key on when processing your transaction
*
* Pro tip: only request this value just before you are going to use it your code
*/
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
console.log("latestBlockhash:", latestBlockhash);

/**
* Create a transaction to be sent to the blockchain
*/
let tx = createTransaction({
version: "legacy",
feePayer: signer,
instructions: [memoIx],
latestBlockhash,
});
console.log("Transaction:");
console.log(tx);

/**
* Sign the transaction with the provided `signer` when it was created
*/
let signedTransaction = await signTransactionMessageWithSigners(tx);
console.log("signedTransaction:");
console.log(signedTransaction);

/**
* Get the transaction signature after it has been signed by at least one signer
*/
let signature = getSignatureFromTransaction(signedTransaction);

/**
* Log the Solana Explorer link for the
*/
console.log("Explorer Link:");
console.log(
getExplorerLink({
cluster,
transaction: signature,
}),
);

try {
/**
* Actually send the transaction to the blockchain and confirm it
*/
await sendAndConfirmTransaction(signedTransaction);

// you can also manually define additional settings for sending your transaction
// await sendAndConfirmTransaction(signedTransaction, {
// commitment: "confirmed",
// skipPreflight: true,
// maxRetries: 10n,
// });

console.log("Transaction confirmed!", signature);
} catch (err) {
console.error("Unable to send and confirm the transaction");
console.error(err);
}
92 changes: 92 additions & 0 deletions examples/tokens/src/2.create-token-mint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {
createSolanaClient,
createTransaction,
generateKeyPairSigner,
getExplorerLink,
getMinimumBalanceForRentExemption,
getSignatureFromTransaction,
signTransactionMessageWithSigners,
} from "gill";
import { loadKeypairSignerFromFile } from "gill/node";
import {
getCreateAccountInstruction,
getCreateMetadataAccountV3Instruction,
getTokenMetadataAddress,
} from "gill/programs";
import {
getInitializeMintInstruction,
getMintSize,
TOKEN_PROGRAM_ADDRESS,
} from "gill/programs/token";

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

const signer = await loadKeypairSignerFromFile();
console.log("signer:", signer.address);

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

const mint = await generateKeyPairSigner();
console.log("mint:", mint.address);

const space = getMintSize();

const metadata = await getTokenMetadataAddress(mint);

const tx = createTransaction({
feePayer: signer,
version: "legacy",
instructions: [
getCreateAccountInstruction({
space,
lamports: getMinimumBalanceForRentExemption(space),
newAccount: mint,
payer: signer,
programAddress: TOKEN_PROGRAM_ADDRESS,
}),
getInitializeMintInstruction(
{
mint: mint.address,
mintAuthority: signer.address,
freezeAuthority: signer.address,
decimals: 9,
},
{
programAddress: TOKEN_PROGRAM_ADDRESS,
},
),
getCreateMetadataAccountV3Instruction({
collectionDetails: null,
isMutable: true,
updateAuthority: signer,
mint: mint.address,
metadata,
mintAuthority: signer,
payer: signer,
data: {
sellerFeeBasisPoints: 0,
collection: null,
creators: null,
uses: null,
name: "super sweet token",
symbol: "SST",
uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/Climate/metadata.json",
},
}),
],
latestBlockhash,
});

const signedTransaction = await signTransactionMessageWithSigners(tx);

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

await sendAndConfirmTransaction(signedTransaction);
49 changes: 49 additions & 0 deletions examples/tokens/src/3.create-token-mint-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
createSolanaClient,
generateKeyPairSigner,
getExplorerLink,
getSignatureFromTransaction,
signTransactionMessageWithSigners,
} from "gill";
import { loadKeypairSignerFromFile } from "gill/node";
import { buildCreateTokenTransaction, TOKEN_2022_PROGRAM_ADDRESS } from "gill/programs/token";

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

const signer = await loadKeypairSignerFromFile();
console.log("signer:", signer.address);

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

const mint = await generateKeyPairSigner();
console.log("mint:", mint.address);

const tx = await buildCreateTokenTransaction({
feePayer: signer,
version: "legacy",
decimals: 9,
metadata: {
isMutable: true,
name: "super sweet token",
symbol: "SST",
uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/Climate/metadata.json",
},
mint,
latestBlockhash,
// defaults to `TOKEN_PROGRAM_ADDRESS`
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
});

const signedTransaction = await signTransactionMessageWithSigners(tx);

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

await sendAndConfirmTransaction(signedTransaction);
Loading

0 comments on commit c79d915

Please sign in to comment.