Skip to content

Commit b2349a6

Browse files
committed
anchor permanent delegate example
1 parent 159244d commit b2349a6

File tree

14 files changed

+259
-8
lines changed

14 files changed

+259
-8
lines changed

tokens/token-2022/mint-close-authority/anchor/programs/mint-close-authority/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub mod mint_close_authority {
2020
use super::*;
2121

2222
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
23-
Initialize::check_mint_data(&ctx.accounts)?;
23+
ctx.accounts.check_mint_data()?;
2424
Ok(())
2525
}
2626

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.anchor
2+
.DS_Store
3+
target
4+
**/*.rs.bk
5+
node_modules
6+
test-ledger
7+
.yarn
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.anchor
2+
.DS_Store
3+
target
4+
node_modules
5+
dist
6+
build
7+
test-ledger
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[toolchain]
2+
3+
[features]
4+
resolution = true
5+
skip-lint = false
6+
7+
[programs.localnet]
8+
permanent_delegate = "A9rxKS84ZoJVyeTfQbCEfxME2vvAM4uwSMjkmhR5XWb1"
9+
10+
[registry]
11+
url = "https://api.apr.dev"
12+
13+
[provider]
14+
cluster = "Localnet"
15+
wallet = "~/.config/solana/id.json"
16+
17+
[scripts]
18+
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[workspace]
2+
members = [
3+
"programs/*"
4+
]
5+
resolver = "2"
6+
7+
[profile.release]
8+
overflow-checks = true
9+
lto = "fat"
10+
codegen-units = 1
11+
[profile.release.build-override]
12+
opt-level = 3
13+
incremental = false
14+
codegen-units = 1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Migrations are an early feature. Currently, they're nothing more than this
2+
// single deploy script that's invoked from the CLI, injecting a provider
3+
// configured from the workspace's Anchor.toml.
4+
5+
const anchor = require("@coral-xyz/anchor");
6+
7+
module.exports = async function (provider) {
8+
// Configure client to use the provider.
9+
anchor.setProvider(provider);
10+
11+
// Add your deploy script here.
12+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"scripts": {
3+
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
4+
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
5+
},
6+
"dependencies": {
7+
"@coral-xyz/anchor": "^0.30.0",
8+
"@solana/spl-token": "^0.4.6"
9+
},
10+
"devDependencies": {
11+
"@types/bn.js": "^5.1.0",
12+
"@types/chai": "^4.3.0",
13+
"@types/mocha": "^9.0.0",
14+
"chai": "^4.3.4",
15+
"mocha": "^9.0.3",
16+
"prettier": "^2.6.2",
17+
"ts-mocha": "^10.0.0",
18+
"typescript": "^4.3.5"
19+
}
20+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "permanent-delegate"
3+
version = "0.1.0"
4+
description = "Created with Anchor"
5+
edition = "2021"
6+
7+
[lib]
8+
crate-type = ["cdylib", "lib"]
9+
name = "permanent_delegate"
10+
11+
[features]
12+
default = []
13+
cpi = ["no-entrypoint"]
14+
no-entrypoint = []
15+
no-idl = []
16+
no-log-ix-name = []
17+
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
18+
19+
[dependencies]
20+
anchor-lang = "0.30.0"
21+
anchor-spl = "0.30.0"
22+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[target.bpfel-unknown-unknown.dependencies.std]
2+
features = []
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use anchor_lang::prelude::*;
2+
use anchor_spl::{
3+
token_2022::spl_token_2022::extension::permanent_delegate::PermanentDelegate,
4+
token_interface::{
5+
spl_pod::optional_keys::OptionalNonZeroPubkey,
6+
spl_token_2022::{
7+
extension::{BaseStateWithExtensions, StateWithExtensions},
8+
state::Mint as MintState,
9+
},
10+
Mint, Token2022,
11+
},
12+
};
13+
14+
declare_id!("A9rxKS84ZoJVyeTfQbCEfxME2vvAM4uwSMjkmhR5XWb1");
15+
16+
#[program]
17+
pub mod permanent_delegate {
18+
use super::*;
19+
20+
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
21+
ctx.accounts.check_mint_data()?;
22+
Ok(())
23+
}
24+
}
25+
26+
#[derive(Accounts)]
27+
pub struct Initialize<'info> {
28+
#[account(mut)]
29+
pub payer: Signer<'info>,
30+
31+
#[account(
32+
init,
33+
payer = payer,
34+
mint::decimals = 2,
35+
mint::authority = payer,
36+
extensions::permanent_delegate::delegate = payer,
37+
)]
38+
pub mint_account: InterfaceAccount<'info, Mint>,
39+
pub token_program: Program<'info, Token2022>,
40+
pub system_program: Program<'info, System>,
41+
}
42+
43+
// helper to check mint data, and demonstrate how to read mint extension data within a program
44+
impl<'info> Initialize<'info> {
45+
pub fn check_mint_data(&self) -> Result<()> {
46+
let mint = &self.mint_account.to_account_info();
47+
let mint_data = mint.data.borrow();
48+
let mint_with_extension = StateWithExtensions::<MintState>::unpack(&mint_data)?;
49+
let extension_data = mint_with_extension.get_extension::<PermanentDelegate>()?;
50+
51+
assert_eq!(
52+
extension_data.delegate,
53+
OptionalNonZeroPubkey::try_from(Some(self.payer.key()))?
54+
);
55+
56+
msg!("{:?}", extension_data);
57+
Ok(())
58+
}
59+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import * as anchor from "@coral-xyz/anchor";
2+
import { Program } from "@coral-xyz/anchor";
3+
import { PermanentDelegate } from "../target/types/permanent_delegate";
4+
import {
5+
TOKEN_2022_PROGRAM_ID,
6+
burnChecked,
7+
createAccount,
8+
getAccount,
9+
mintTo,
10+
} from "@solana/spl-token";
11+
12+
describe("permanent-delegate", () => {
13+
const provider = anchor.AnchorProvider.env();
14+
const connection = provider.connection;
15+
const wallet = provider.wallet as anchor.Wallet;
16+
anchor.setProvider(provider);
17+
18+
const program = anchor.workspace
19+
.PermanentDelegate as Program<PermanentDelegate>;
20+
21+
const mintKeypair = new anchor.web3.Keypair();
22+
23+
it("Create Mint with Permanent Delegate", async () => {
24+
const transactionSignature = await program.methods
25+
.initialize()
26+
.accounts({ mintAccount: mintKeypair.publicKey })
27+
.signers([mintKeypair])
28+
.rpc({ skipPreflight: true });
29+
console.log("Your transaction signature", transactionSignature);
30+
});
31+
32+
it("Create Token Account, Mint Tokens, and burn with Permanent Delegate", async () => {
33+
const amount = 100;
34+
35+
// Random keypair to use as owner of Token Account
36+
const randomKeypair = new anchor.web3.Keypair();
37+
38+
// Create Token Account owned by random keypair
39+
const sourceTokenAccount = await createAccount(
40+
connection,
41+
wallet.payer, // Payer to create Token Account
42+
mintKeypair.publicKey, // Mint Account address
43+
randomKeypair.publicKey, // Token Account owner
44+
undefined, // Optional keypair, default to Associated Token Account
45+
undefined, // Confirmation options
46+
TOKEN_2022_PROGRAM_ID // Token Extension Program ID
47+
);
48+
49+
// Mint tokens to sourceTokenAccount
50+
await mintTo(
51+
connection,
52+
wallet.payer, // Transaction fee payer
53+
mintKeypair.publicKey, // Mint Account address
54+
sourceTokenAccount, // Mint to
55+
wallet.publicKey, // Mint Authority address
56+
amount, // Amount
57+
undefined, // Additional signers
58+
undefined, // Confirmation options
59+
TOKEN_2022_PROGRAM_ID // Token Extension Program ID
60+
);
61+
62+
// Burn tokens from sourceTokenAccount, using Permanent Delegate
63+
// The permanent delegate can burn / transfer tokens from all token account for the mint account
64+
const transactionSignature = await burnChecked(
65+
connection,
66+
wallet.payer, // Transaction fee payer
67+
sourceTokenAccount, // Tranfer from
68+
mintKeypair.publicKey, // Mint Account address
69+
wallet.publicKey, // Use Permanent Delegate as owner
70+
amount, // Amount
71+
2, // Mint Account decimals
72+
undefined, // Additional signers
73+
undefined, // Confirmation options
74+
TOKEN_2022_PROGRAM_ID // Token Extension Program ID
75+
);
76+
console.log("Your transaction signature", transactionSignature);
77+
78+
const tokenAccount = await getAccount(
79+
connection,
80+
sourceTokenAccount,
81+
null,
82+
TOKEN_2022_PROGRAM_ID
83+
);
84+
console.log("Token Account Balance:", Number(tokenAccount.amount));
85+
});
86+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"types": ["mocha", "chai"],
4+
"typeRoots": ["./node_modules/@types"],
5+
"lib": ["es2015"],
6+
"module": "commonjs",
7+
"target": "es6",
8+
"esModuleInterop": true
9+
}
10+
}

tokens/token-2022/transfer-fees/anchor/programs/transfer-fee/src/instructions/initialize.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ pub fn process_initialize(
8888
Some(&ctx.accounts.payer.key()), // freeze authority
8989
)?;
9090

91-
Initialize::check_mint_data(&ctx.accounts)?;
92-
91+
ctx.accounts.check_mint_data()?;
9392
Ok(())
9493
}
9594

tokens/token-2022/transfer-fees/anchor/tests/transfer-fee.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,6 @@ describe("transfer-fee", () => {
110110
isSigner: false,
111111
isWritable: true,
112112
},
113-
{
114-
pubkey: new anchor.web3.Keypair().publicKey,
115-
isSigner: false,
116-
isWritable: true,
117-
},
118113
])
119114
.rpc({ skipPreflight: true });
120115
console.log("Your transaction signature", transactionSignature);

0 commit comments

Comments
 (0)