Skip to content

Commit

Permalink
demo starter code
Browse files Browse the repository at this point in the history
  • Loading branch information
ixmorrow committed Dec 9, 2022
0 parents commit 7a7c986
Show file tree
Hide file tree
Showing 13 changed files with 1,563 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

.anchor
.DS_Store
target
**/*.rs.bk
node_modules
test-ledger
8 changes: 8 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

.anchor
.DS_Store
target
node_modules
dist
build
test-ledger
15 changes: 15 additions & 0 deletions Anchor.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[features]
seeds = false
skip-lint = false
[programs.localnet]
bump_seed_canonicalization = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"

[registry]
url = "https://api.apr.dev"

[provider]
cluster = "localnet"
wallet = "/home/ixmorrow/.config/solana/id.json"

[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
13 changes: 13 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[workspace]
members = [
"programs/*"
]

[profile.release]
overflow-checks = true
lto = "fat"
codegen-units = 1
[profile.release.build-override]
opt-level = 3
incremental = false
codegen-units = 1
12 changes: 12 additions & 0 deletions migrations/deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Migrations are an early feature. Currently, they're nothing more than this
// single deploy script that's invoked from the CLI, injecting a provider
// configured from the workspace's Anchor.toml.

const anchor = require("@project-serum/anchor");

module.exports = async function (provider) {
// Configure client to use the provider.
anchor.setProvider(provider);

// Add your deploy script here.
};
19 changes: 19 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"scripts": {
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
},
"dependencies": {
"@project-serum/anchor": "^0.25.0"
},
"devDependencies": {
"chai": "^4.3.4",
"mocha": "^9.0.3",
"ts-mocha": "^10.0.0",
"@types/bn.js": "^5.1.0",
"@types/chai": "^4.3.0",
"@types/mocha": "^9.0.0",
"typescript": "^4.3.5",
"prettier": "^2.6.2"
}
}
19 changes: 19 additions & 0 deletions programs/bump-seed-canonicalization/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "bump-seed-canonicalization"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]
name = "bump_seed_canonicalization"

[features]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
default = []

[dependencies]
anchor-lang = "0.25.0"
2 changes: 2 additions & 0 deletions programs/bump-seed-canonicalization/Xargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
118 changes: 118 additions & 0 deletions programs/bump-seed-canonicalization/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use anchor_lang::prelude::*;
use borsh::{BorshDeserialize, BorshSerialize};

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod bump_seed_canonicalization {
use super::*;

// insecure, allows for creation of multiple accounts for given set of seeds
pub fn initialize(ctx: Context<Initialize>, bump_seed: u8) -> Result<()> {
let space = 32;
let lamports = Rent::get()?.minimum_balance(space as usize);

let ix = anchor_lang::solana_program::system_instruction::create_account(
&ctx.accounts.payer.key(),
&ctx.accounts.pda.key(),
lamports,
space,
&ctx.program_id,
);

anchor_lang::solana_program::program::invoke_signed(
&ix,
&[
ctx.accounts.payer.to_account_info(),
ctx.accounts.pda.to_account_info(),
ctx.accounts.system_program.to_account_info(),
],
&[&[&[bump_seed]]],
)?;

let mut account = User::try_from_slice(&ctx.accounts.pda.data.borrow()).unwrap();

account.user = ctx.accounts.payer.key();
account.serialize(&mut *ctx.accounts.pda.data.borrow_mut())?;

msg!("PDA: {}", ctx.accounts.pda.key());
msg!("User: {}", account.user);

Ok(())
}

pub fn insecure(ctx: Context<Unchecked>, bump_seed: u8) -> Result<()> {
let address = Pubkey::create_program_address(&[&[bump_seed]], ctx.program_id).unwrap();
if address != ctx.accounts.pda.key() {
return Err(ProgramError::InvalidArgument.into());
}

let account = User::try_from_slice(&ctx.accounts.pda.data.borrow()).unwrap();

msg!("PDA: {}", ctx.accounts.pda.key());
msg!("User: {}", account.user);
Ok(())
}
}

#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
/// CHECK:
pub pda: AccountInfo<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Unchecked<'info> {
/// CHECK:
pda: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct Checked<'info> {
#[account(seeds = [], bump)]
pda: Account<'info, UserAccount>,
}

#[derive(BorshSerialize, BorshDeserialize, Clone)]
pub struct User {
user: Pubkey,
}

// Anchor account
#[account]
pub struct Data {
value: u64,
// bump field
bump: u8
}



/* ************************************************************ */

pub const DATA_PDA_SEED: &str = "test-seed";

#[derive(Clone)]
pub struct UserAccount(User);

impl anchor_lang::Owner for UserAccount {
fn owner() -> Pubkey {
ID
}
}

impl anchor_lang::AccountSerialize for UserAccount {}

impl anchor_lang::AccountDeserialize for UserAccount {
fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
User::deserialize(buf).map(Self).map_err(Into::into)
}

fn try_deserialize(buf: &mut &[u8]) -> Result<Self> {
Self::try_deserialize_unchecked(buf)
}
}
140 changes: 140 additions & 0 deletions tests/bump-seed-canonicalization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import * as anchor from "@project-serum/anchor"
import { Program } from "@project-serum/anchor"
import {
findProgramAddressSync,
} from "@project-serum/anchor/dist/cjs/utils/pubkey"
import { expect } from "chai"
import { BumpSeedCanonicalization } from "../target/types/bump_seed_canonicalization"
import { PublicKey, Keypair, SystemProgram } from '@solana/web3.js'
import { safeAirdrop, findNonCanonicalPda } from './utils/utils'
import { BN } from "bn.js"

describe("bump-seed-canonicalization", async () => {
// Initialize testing environment
anchor.setProvider(anchor.AnchorProvider.env())
const provider = anchor.AnchorProvider.env()
const program = anchor.workspace.BumpSeedCanonicalization as Program<BumpSeedCanonicalization>

// payer for creation of accounts
const payer = Keypair.generate()

// derive first PDA using canonical bump
const [pda, bump] = findProgramAddressSync([], program.programId)
console.log("First canonical PDA:", pda.toString())
console.log("Canonical bump:", bump)

// derive second PDA using a non-canonical bump
const [pda_not_canonical, not_canonical_bump] = await findNonCanonicalPda(
[],
program.programId
)
console.log("First non-canonical PDA:", pda_not_canonical.toString())
console.log("Non-canonical bump:", not_canonical_bump)


it("Initialize PDA using canonical bump", async () => {
await program.methods.initialize(bump).accounts({ pda: pda }).rpc()
})

it("Initialize PDA using non-canonical bump", async () => {
await program.methods
.initialize(not_canonical_bump)
.accounts({ pda: pda_not_canonical })
.rpc()
})

it("Verify PDA with canonical bump", async () => {
await program.methods.insecure(bump).accounts({ pda: pda }).rpc()
})

it("Verify PDA with non-canonical bump", async () => {
await program.methods
.insecure(not_canonical_bump)
.accounts({ pda: pda_not_canonical })
.rpc()
})

// it("Create new account with canonnical bump via Anchor constraints", async () => {
// // payer needs SOL to pay for account creation
// await safeAirdrop(payer.publicKey, provider.connection)

// const pda_seed = "test-seed"
// const value = 55
// const [pda_canonical, canonical_bump] = await PublicKey.findProgramAddress(
// [Buffer.from(pda_seed)],
// program.programId
// )

// console.log("Second canonical PDA:", pda_canonical.toString())
// console.log("Canonical bump:", canonical_bump)

// await program.methods.initializeWithAnchor(new BN(value))
// .accounts({
// payer: payer.publicKey,
// data: pda_canonical,
// systemProgram: SystemProgram.programId
// })
// .signers([payer])
// .rpc()
// })

// // this test should fail because Anchor will not initalize an account at a PDA that is not derived with the canonical bump
// it("Create new account with non-canonnical bump via Anchor constraints (should fail)", async () => {
// // same seed as test above
// const pda_seed = "test-seed"
// // derive PDA using the same seed as before, but use a different bump that is not the canonical bump
// const [non_canonical_pda, non_canonical_bump] = await findNonCanonicalPda(
// [Buffer.from(pda_seed)],
// program.programId
// )
// console.log("Second non-canonical PDA:", non_canonical_pda.toString())
// console.log("Non-canonical bump:", non_canonical_bump)
// try {
// await program.methods.initializeWithAnchor(new BN(non_canonical_bump))
// .accounts({
// payer: payer.publicKey,
// data: non_canonical_pda,
// systemProgram: SystemProgram.programId
// })
// .signers([payer])
// .rpc()
// } catch (e) {
// console.log(e.message)
// expect(e.message).to.eq("failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account")
// }
// })

// it("Verify address of account PDA via Anchor constraints with canonical bump", async () => {
// const pda_seed = "test-seed"
// const [pda_canonical, canonical_bump] = await PublicKey.findProgramAddress(
// [Buffer.from(pda_seed)],
// program.programId
// )

// await program.methods.verifyAddress()
// .accounts({
// data: pda_canonical,
// })
// .rpc()
// })

// it("Try to verify address of non-canonical pda (should fail)", async () => {
// const pda_seed = "test-seed"
// const [non_canonical_pda, non_canonical_bump] = await findNonCanonicalPda(
// [Buffer.from(pda_seed)],
// program.programId
// )

// try {
// const createAcctTx = await program.methods.verifyAddress()
// .accounts({
// data: non_canonical_pda,
// })
// .rpc()
// console.log("Verify PDA account via Anchor constraints: ", createAcctTx)
// } catch (e) {
// console.log(e.message)
// expect(e.message).to.eq("AnchorError caused by account: data. Error Code: AccountNotInitialized. Error Number: 3012. Error Message: The program expected this account to be already initialized.")
// }
// })
})
Loading

0 comments on commit 7a7c986

Please sign in to comment.