Browse Source

destroy account example

ohaddahan 3 years ago
parent
commit
0d93eec785
17 changed files with 295 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 7 0
      basics/destroy-an-account/anchor/destroy-an-account/.gitignore
  3. 8 0
      basics/destroy-an-account/anchor/destroy-an-account/.prettierignore
  4. 15 0
      basics/destroy-an-account/anchor/destroy-an-account/Anchor.toml
  5. 13 0
      basics/destroy-an-account/anchor/destroy-an-account/Cargo.toml
  6. 12 0
      basics/destroy-an-account/anchor/destroy-an-account/migrations/deploy.ts
  7. 19 0
      basics/destroy-an-account/anchor/destroy-an-account/package.json
  8. 19 0
      basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/Cargo.toml
  9. 2 0
      basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/Xargo.toml
  10. 35 0
      basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/instructions/create_user.rs
  11. 25 0
      basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/instructions/destroy_user.rs
  12. 5 0
      basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/instructions/mod.rs
  13. 20 0
      basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/lib.rs
  14. 1 0
      basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/state/mod.rs
  15. 18 0
      basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/state/user.rs
  16. 85 0
      basics/destroy-an-account/anchor/destroy-an-account/tests/destroy-an-account.ts
  17. 10 0
      basics/destroy-an-account/anchor/destroy-an-account/tsconfig.json

+ 1 - 0
.gitignore

@@ -1,4 +1,5 @@
 .template
+.idea
 
 test-ledger/
 

+ 7 - 0
basics/destroy-an-account/anchor/destroy-an-account/.gitignore

@@ -0,0 +1,7 @@
+
+.anchor
+.DS_Store
+target
+**/*.rs.bk
+node_modules
+test-ledger

+ 8 - 0
basics/destroy-an-account/anchor/destroy-an-account/.prettierignore

@@ -0,0 +1,8 @@
+
+.anchor
+.DS_Store
+target
+node_modules
+dist
+build
+test-ledger

+ 15 - 0
basics/destroy-an-account/anchor/destroy-an-account/Anchor.toml

@@ -0,0 +1,15 @@
+[features]
+seeds = false
+skip-lint = false
+[programs.localnet]
+destroy_an_account = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "localnet"
+wallet = "/Users/ohaddahan/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

+ 13 - 0
basics/destroy-an-account/anchor/destroy-an-account/Cargo.toml

@@ -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 - 0
basics/destroy-an-account/anchor/destroy-an-account/migrations/deploy.ts

@@ -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 - 0
basics/destroy-an-account/anchor/destroy-an-account/package.json

@@ -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 - 0
basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "destroy-an-account"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "destroy_an_account"
+
+[features]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = "0.25.0"

+ 2 - 0
basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/Xargo.toml

@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []

+ 35 - 0
basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/instructions/create_user.rs

@@ -0,0 +1,35 @@
+use crate::state::user::User;
+use anchor_lang::prelude::*;
+
+#[derive(AnchorSerialize, AnchorDeserialize)]
+pub struct CreateUserArgs {
+    pub name: String,
+}
+
+#[derive(Accounts)]
+#[instruction(args: CreateUserArgs)]
+pub struct CreateUserContext<'info> {
+    #[account(mut)]
+    pub user: Signer<'info>,
+    #[account(
+    init,
+    seeds=[User::PREFIX.as_bytes(), user.key().as_ref()],
+    payer=user,
+    space=User::SIZE,
+    bump
+    )]
+    pub user_account: Box<Account<'info, User>>,
+    pub system_program: Program<'info, System>,
+    pub rent: Sysvar<'info, Rent>,
+}
+
+pub fn create_user(ctx: Context<CreateUserContext>, args: CreateUserArgs) -> Result<()> {
+    let user = &ctx.accounts.user;
+    let user_account = &mut ctx.accounts.user_account;
+
+    user_account.bump = *ctx.bumps.get("user_account").unwrap();
+    user_account.user = user.key();
+    user_account.name = args.name;
+
+    Ok(())
+}

+ 25 - 0
basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/instructions/destroy_user.rs

@@ -0,0 +1,25 @@
+use crate::state::user::User;
+use anchor_lang::prelude::*;
+use anchor_lang::AccountsClose;
+
+#[derive(Accounts)]
+pub struct DestroyUserContext<'info> {
+    #[account(mut)]
+    pub user: Signer<'info>,
+    #[account(
+    mut,
+    seeds=[User::PREFIX.as_bytes(), user_account.user.key().as_ref()],
+    has_one=user,
+    bump=user_account.bump
+    )]
+    pub user_account: Box<Account<'info, User>>,
+    pub system_program: Program<'info, System>,
+    pub rent: Sysvar<'info, Rent>,
+}
+
+pub fn destroy_user(ctx: Context<DestroyUserContext>) -> Result<()> {
+    let user = &mut ctx.accounts.user;
+    let user_account = &mut ctx.accounts.user_account;
+    user_account.close(user.to_account_info())?;
+    Ok(())
+}

+ 5 - 0
basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/instructions/mod.rs

@@ -0,0 +1,5 @@
+pub mod create_user;
+pub mod destroy_user;
+
+pub use create_user::*;
+pub use destroy_user::*;

+ 20 - 0
basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/lib.rs

@@ -0,0 +1,20 @@
+use anchor_lang::prelude::*;
+
+mod instructions;
+mod state;
+use instructions::*;
+
+declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+#[program]
+pub mod destroy_an_account {
+    use super::*;
+
+    pub fn create_user(ctx: Context<CreateUserContext>, args: CreateUserArgs) -> Result<()> {
+        create_user::create_user(ctx, args)
+    }
+
+    pub fn destroy_user(ctx: Context<DestroyUserContext>) -> Result<()> {
+        destroy_user::destroy_user(ctx)
+    }
+}

+ 1 - 0
basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/state/mod.rs

@@ -0,0 +1 @@
+pub mod user;

+ 18 - 0
basics/destroy-an-account/anchor/destroy-an-account/programs/destroy-an-account/src/state/user.rs

@@ -0,0 +1,18 @@
+use anchor_lang::prelude::*;
+
+#[account]
+pub struct User {
+    pub bump: u8,
+    pub user: Pubkey,
+    pub name: String,
+}
+
+impl User {
+    pub const PREFIX: &'static str = "USER";
+
+    pub const SIZE: usize = 8 + /* discriminator */
+        std::mem::size_of::<u8>() + /* bump */
+        std::mem::size_of::<Pubkey>() + /* user */
+        80 /* name */
+    ;
+}

+ 85 - 0
basics/destroy-an-account/anchor/destroy-an-account/tests/destroy-an-account.ts

@@ -0,0 +1,85 @@
+import * as anchor from "@project-serum/anchor";
+import { Program } from "@project-serum/anchor";
+import {Keypair, LAMPORTS_PER_SOL} from "@solana/web3.js";
+import { DestroyAnAccount } from "../target/types/destroy_an_account";
+import {BlockheightBasedTransactionConfirmationStrategy, PublicKey} from "@solana/web3.js";
+import assert from "assert";
+
+const PROGRAM_ID = new PublicKey("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+
+export async function airdrop(program: Program<any>, receiver: PublicKey, amount: number) {
+    const sig = await program.provider.connection.requestAirdrop(receiver, amount);
+    const blockStats = await program.provider.connection.getLatestBlockhash();
+    const strategy: BlockheightBasedTransactionConfirmationStrategy = {
+        signature: sig,
+        blockhash: blockStats.blockhash,
+        lastValidBlockHeight: blockStats.lastValidBlockHeight
+    }
+    await program.provider.connection.confirmTransaction(strategy, "confirmed");
+}
+
+export async function getUserAccount(user: PublicKey): Promise<[PublicKey, number]> {
+    return await PublicKey.findProgramAddress(
+        [
+            Buffer.from(anchor.utils.bytes.utf8.encode("USER")),
+            user.toBuffer()
+        ], PROGRAM_ID)
+}
+
+
+describe("destroy-an-account", () => {
+    // Configure the client to use the local cluster.
+    anchor.setProvider(anchor.AnchorProvider.env());
+
+    const program = anchor.workspace.DestroyAnAccount as Program<DestroyAnAccount>;
+    const connection = program.provider.connection;
+    const user = Keypair.generate();
+
+    it("Airdrop", async () => {
+        const balanceBefore = await connection.getBalance(user.publicKey);
+        await airdrop(program, user.publicKey, LAMPORTS_PER_SOL);
+        const balanceAfter = await connection.getBalance(user.publicKey);
+        assert.equal(balanceAfter, balanceBefore + LAMPORTS_PER_SOL);
+    });
+
+
+    it("Create Account", async () => {
+        const [userAccountAddress] = await getUserAccount(user.publicKey);
+        const userAccountBefore = await program.account.user.fetchNullable(userAccountAddress, "processed");
+        assert.equal(userAccountBefore, null);
+
+        await program.methods
+            .createUser({
+                name: "John Doe"
+            })
+            .accounts({
+                user: user.publicKey,
+                userAccount: userAccountAddress
+            })
+            .signers([user])
+            .rpc({commitment: "confirmed"});
+
+        const userAccountAfter = await program.account.user.fetchNullable(userAccountAddress, "processed");
+        assert.notEqual(userAccountAfter, null);
+        assert.equal(userAccountAfter.name, "John Doe");
+        assert.equal(userAccountAfter.user.toBase58(), user.publicKey.toBase58());
+    })
+
+    it("Destroy Account", async () => {
+        const [userAccountAddress] = await getUserAccount(user.publicKey);
+        const userAccountBefore = await program.account.user.fetchNullable(userAccountAddress, "processed");
+        assert.notEqual(userAccountBefore, null);
+
+        await program.methods
+            .destroyUser()
+            .accounts({
+                user: user.publicKey,
+                userAccount: userAccountAddress
+            })
+            .signers([user])
+            .rpc({commitment: "confirmed"});
+
+        const userAccountAfter = await program.account.user.fetchNullable(userAccountAddress, "processed");
+        assert.equal(userAccountAfter, null);
+    })
+});

+ 10 - 0
basics/destroy-an-account/anchor/destroy-an-account/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "typeRoots": ["./node_modules/@types"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true
+  }
+}