Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix and improve token-program.md,token-program-advance.md and close-mint.md #342

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 16 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
28 changes: 21 additions & 7 deletions content/courses/token-extensions/close-mint.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,10 @@ await setAuthority(

## Lab

In this lab, we'll create a mint with the `close mint` extension. We will then
mint some of the tokens and see what happens when we try to close it with a
non-zero supply (hint, the close transaction will fail). Lastly, we will burn
the supply and close the account.
In this lab, we'll create a token mint account with the `close mint` extension.
We will then mint some of the tokens and see what happens when we try to close
it with a non-zero supply (hint, the close transaction will fail). Lastly, we
will burn the supply and close the account.

### 1. Getting Started

Expand Down Expand Up @@ -304,6 +304,14 @@ running `solana config get` in your terminal. And then go to
address. You can get your address from running `solana address` in your
terminal.

For example, assuming `keypairPath` is `/home/.config/solana/id.json`

```typescript
const payer = initializeKeypair(connection, {
keypairPath: "/home/.config/solana/id.json",
});
```

### 3. Create a mint with close authority

Let's create a closable mint by creating the function `createClosableMint` in a
Expand Down Expand Up @@ -399,7 +407,13 @@ export async function createClosableMint(
```

Now let's call this function in `src/index.ts`. First you'll need to import our
new function. Then paste the following under the right comment section:
new function by uncommenting the 3rd line.

```ts
import { createClosableMint } from "./create-mint";
```

Then paste the following under the right comment section:

```ts
// CREATE A MINT WITH CLOSE AUTHORITY
Expand Down Expand Up @@ -470,7 +484,7 @@ Underneath the minting functions, add the following code block:
/**
* Get mint information to verify supply
*/
const mintInfo = await getMint(
let mintInfo = await getMint(
connection,
mintKeypair.publicKey,
"finalized",
Expand Down Expand Up @@ -591,7 +605,7 @@ Putting this all together we get:

```ts
// CLOSE MINT
const mintInfo = await getMint(
mintInfo = await getMint(
connection,
mintKeypair.publicKey,
"finalized",
Expand Down
99 changes: 82 additions & 17 deletions content/courses/tokens-and-nfts/token-program-advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Under the hood, the `burn` function creates a transaction with instructions
obtained from the `createBurnInstruction` function:

```typescript
import { PublicKey, Transaction } from "@solana/web3";
import { PublicKey, Transaction } from "@solana/web3.js";
import { createBurnInstruction } from "@solana/spl-token";

async function buildBurnTransaction(
Expand Down Expand Up @@ -105,15 +105,15 @@ Under the hood, the `approve` function creates a transaction with instructions
obtained from the `createApproveInstruction` function:

```typescript
import { PublicKey, Transaction } from "@solana/web3";
import { PublicKey, Transaction } from "@solana/web3.js";
import { createApproveInstruction } from "@solana/spl-token";

async function buildApproveTransaction(
account: PublicKey,
delegate: PublicKey,
owner: PublicKey,
amount: number,
): Promise<web3.Transaction> {
): Promise<Transaction> {
const transaction = new Transaction().add(
createApproveInstruction(account, delegate, owner, amount),
);
Expand Down Expand Up @@ -150,13 +150,13 @@ Under the hood, the `revoke` function creates a transaction with instructions
obtained from the `createRevokeInstruction` function:

```typescript
import { PublicKey, Transaction } from "@solana/web3";
import { PublicKey, Transaction } from "@solana/web3.js";
import { revoke } from "@solana/spl-token";

async function buildRevokeTransaction(
account: PublicKey,
owner: PublicKey,
): Promise<web3.Transaction> {
): Promise<Transaction> {
const transaction = new Transaction().add(
createRevokeInstruction(account, owner),
);
Expand All @@ -181,7 +181,8 @@ previous lab, you can
[add a second account on devnet](/content/courses/intro-to-solana/intro-to-cryptography.md)
if you like, or find a friend who has a devnet account!

Create a new file `delegate-tokens.ts`
Create a new file `delegate-tokens.ts`. We use the system program account as the
delegate here for demonstration.

```typescript
import "dotenv/config";
Expand All @@ -204,8 +205,8 @@ console.log(
`🔑 Loaded our keypair securely, using an env file! Our public key is: ${user.publicKey.toBase58()}`,
);

// Add the delegate public key here.
const delegate = new PublicKey("YOUR_DELEGATE_HERE");
// Use the system program public key
const delegate = new PublicKey("11111111111111111111111111111111");

// Substitute in your token mint account
const tokenMintAccount = new PublicKey("YOUR_TOKEN_MINT_ADDRESS_HERE");
Expand All @@ -231,24 +232,62 @@ const approveTransactionSignature = await approve(
);

console.log(
`Approve Delegate Transaction: ${getExplorerLink(
`Approve Delegate Transaction: ${getExplorerLink(
"transaction",
approveTransactionSignature,
"devnet",
)}`,
);
```

Replace `YOUR_TOKEN_MINT_ADDRESS_HERE` with your mint token address obtained
from the previous chapter.

Run the script using `npx esrun delegate-tokens.ts`. You should see:

```bash
✅ Approve Delegate Transaction: https://explorer.solana.com/tx/3sBr62x2VMaoJ4Z3SQMy6ZPzQKaa5Bs9ni9dgwwZZ5qEViKh1gQznCgH489h6pgfruMmqPbc2GgminTPK4UXRRZd?cluster=devnet
```

Open the Explorer link, you will see the ‌approval information.

#### 2. Revoke Delegate

Lets revoke the `delegate` using the `spl-token` library's `revoke` function.

Revoke will set delegate for the token account to null and reset the delegated
amount to 0.
Revoke will set delegate for the associated token account to null and reset the
delegated amount to 0.

All we will need for this function is the token account and user. After the
Create a new file `revoke-approve-tokens.ts`.

```typescript
import "dotenv/config";
import {
getExplorerLink,
getKeypairFromEnvironment,
} from "@solana-developers/helpers";
import { Connection, PublicKey, clusterApiUrl } from "@solana/web3.js";
import { getOrCreateAssociatedTokenAccount, revoke } from "@solana/spl-token";

const connection = new Connection(clusterApiUrl("devnet"));

const user = getKeypairFromEnvironment("SECRET_KEY");

console.log(
`🔑 Loaded our keypair securely, using an env file! Our public key is: ${user.publicKey.toBase58()}`,
);

// Substitute in your token mint account
const tokenMintAccount = new PublicKey("YOUR_TOKEN_MINT_ADDRESS_HERE");

// Get or create the source and destination token accounts to store this token
const sourceTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
user,
tokenMintAccount,
user.publicKey,
);

const revokeTransactionSignature = await revoke(
connection,
user,
Expand All @@ -257,22 +296,33 @@ const revokeTransactionSignature = await revoke(
);

console.log(
`Revoke Delegate Transaction: ${getExplorerLink(
`Revoke Delegate Transaction: ${getExplorerLink(
"transaction",
revokeTransactionSignature,
"devnet",
)}`,
);
```

Replace `YOUR_TOKEN_MINT_ADDRESS_HERE` with your mint token address obtained
from the previous chapter.

Run the script using `npx esrun revoke-approve-tokens.ts`. You should see:

```bash
✅ Revoke Delegate Transaction: https://explorer.solana.com/tx/5UboxLULHT3pPznBxThfQMc73NNjYNLmvqrB3JVVXPwWxUFWA49WG58sFQP8B5rv4FXxxZm3mur319YNiyYxYgBd?cluster=devnet
```

Open the Explorer link, you will see the revoke information.

#### 3. Burn Tokens

Finally, let's remove some tokens from circulation by burning them.

Use the `spl-token` library's `burn` function to remove half of your tokens from
circulation.

Now call this new function in `main` to burn 25 of the user's tokens.
Create a new file `burn-tokens.ts`.

```typescript
import "dotenv/config";
Expand All @@ -281,7 +331,11 @@ import {
getKeypairFromEnvironment,
} from "@solana-developers/helpers";
import { Connection, PublicKey, clusterApiUrl } from "@solana/web3.js";
import { getOrCreateAssociatedTokenAccount, burn } from "@solana/spl-token";
import {
getOrCreateAssociatedTokenAccount,
Account,
burn,
} from "@solana/spl-token";

const connection = new Connection(clusterApiUrl("devnet"));

Expand All @@ -294,7 +348,7 @@ console.log(
// Substitute in your token mint account
const tokenMintAccount = new PublicKey("YOUR_TOKEN_MINT_ADDRESS_HERE");

// Get the account where the user stores these tokens
// Get or create the source and destination token accounts to store this token
const sourceTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
user,
Expand All @@ -315,14 +369,25 @@ const transactionSignature = await burn(
);

console.log(
`Burn Transaction: ${getExplorerLink(
`Burn Transaction: ${getExplorerLink(
"transaction",
transactionSignature,
"devnet",
)}`,
);
```

Replace `YOUR_TOKEN_MINT_ADDRESS_HERE` with your mint token address obtained
from the previous chapter.

Run the script using `npx esrun burn-tokens.ts`. You should see:

```bash
✅ Burn Transaction: https://explorer.solana.com/tx/P9JAK7bSAhycccGunDEThgt12QFiqMr9oexenEmRXXKoXsLKr2x64k9BWNppjTxFeVMUYjBEncRKe3gZsyd29JY?cluster=devnet
```

Open the Explorer link, you will see the burn information.

Well done! You've now

<Callout type="success">
Expand Down
33 changes: 25 additions & 8 deletions content/courses/tokens-and-nfts/token-program.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ description:
- Creating Token Mints and Token Accounts requires allocating **rent** in SOL.
The rent for a Token Account can be refunded when the account is closed.
Additionally, tokens created with the
[Token Extensions Program](/developers/courses/token-extensions-for-mints/close-mint)
[Token Extensions Program](/content/courses/token-extensions/close-mint.md)
can also close Token Mints.

### Lesson
Expand Down Expand Up @@ -617,17 +617,20 @@ const transactionLink = getExplorerLink(
"devnet",
);

console.log(`✅ Transaction confirmed, explorer link is: ${transactionLink}!`);
console.log(`✅ Transaction confirmed, explorer link is: ${transactionLink}`);

const tokenMintLink = getExplorerLink(
"address",
tokenMintAccount.toString(),
"devnet",
);

console.log(`✅ Look at the token mint again: ${tokenMintLink}!`);
console.log(`✅ Look at the token mint again: ${tokenMintLink}`);
```

Replace `YOUR_TOKEN_MINT_ADDRESS_HERE` with your address of the mint and Run the
script using `npx esrun create-token-metadata.ts`.

You'll now see Solana Explorer is updated, showing the token's name and symbol
on the mint!

Expand Down Expand Up @@ -697,7 +700,7 @@ const link = getExplorerLink(
console.log(`✅ Created token Account: ${link}`);
```

Run the script using `npx esrun create-token-mint.ts`. You should see:
Run the script using `npx esrun create-token-account.ts`. You should see:

```bash
✅ Success! Created token account: https://explorer.solana.com/address/CTjoLdEeK8rk4YWYW9ZqACyjHexbYKH3hEoagHxLVEFs?cluster=devnet
Expand All @@ -707,14 +710,17 @@ Open the token account in Solana Explorer. Look at the owner - it's the account
you made the ATA for! The balance will be zero, as we haven't sent any tokens
there yet. Let's mint some tokens there and fix that!

Remember the address of your token account ! We'll use it to mint tokens.

#### Mint Tokens

Now that we have a token mint and a token account, let's mint tokens to the
token account. Recall that we set the `user` as the `mintAuthority` for the
`mint` we created.

Create a function `mintTokens` that uses the `spl-token` function `mintTo` to
mint tokens:
Create an empty file called `mint-tokens.ts`. Then uses the `spl-token` function
`mintTo()` to mint tokens. Remember to substitute in your token mint address and
token account address below!

```typescript
import { mintTo } from "@solana/spl-token";
Expand Down Expand Up @@ -776,6 +782,10 @@ associated token account - we can just look it up using
mint of the token we want to send. Likewise, we can find (or make) an ATA for
our recipient to hold this token too.

Create an empty file called `transfer-tokens.ts`. Then replace
`YOUR_RECIPIENT_HERE` with your recipient public key and replace
`YOUR_TOKEN_MINT_ADDRESS_HERE` with your token mint address.

```typescript
import "dotenv/config";
import {
Expand Down Expand Up @@ -803,14 +813,15 @@ const MINOR_UNITS_PER_MAJOR_UNITS = Math.pow(10, 2);

console.log(`💸 Attempting to send 1 token to ${recipient.toBase58()}...`);

// Get or create the source and destination token accounts to store this token
// Get or create the source token account to store this token
const sourceTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
sender,
tokenMintAccount,
sender.publicKey,
);

// Get or create the destination token account to store this token
const destinationTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
sender,
Expand All @@ -830,7 +841,13 @@ const signature = await transfer(

const explorerLink = getExplorerLink("transaction", signature, "devnet");

console.log(`✅ Transaction confirmed, explorer link is: ${explorerLink}!`);
console.log(`✅ Transaction confirmed, explorer link is: ${explorerLink}`);
```

Run the script using `npx esrun transfer-tokens.ts`. You should see:

```bash
✅ Transaction confirmed, explorer link is: https://explorer.solana.com/tx/SgV2j2DkaErYf7ERiB11USoZzGqAk8HPEqVJLP8HWdz9M61FSFgyEMXJycHQtfCooCAPBom7Vi3akEAwSUHQUsu?cluster=devnet
```

Open the Explorer link. You see your balance go down, and the recipient's
Expand Down
Loading