Browse Source

Fixed dependency issues. Simplified attach. Cargo fmt (#400)

Tiago Carvalho 2 months ago
parent
commit
69d6179261
21 changed files with 196 additions and 351 deletions
  1. 1 1
      tokens/token-2022/transfer-hook/allow-block-list-token/.gitignore
  2. 4 3
      tokens/token-2022/transfer-hook/allow-block-list-token/README.md
  3. 1 1
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/Anchor.toml
  4. 1 2
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/constants.rs
  5. 1 1
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/errors.rs
  6. 12 93
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/attach_to_mint.rs
  7. 3 7
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/change_mode.rs
  8. 1 3
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/init_config.rs
  9. 4 16
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/init_mint.rs
  10. 8 9
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/mod.rs
  11. 5 5
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/lib.rs
  12. 5 3
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/state.rs
  13. 0 3
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/utils.rs
  14. 17 14
      tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/tests/test.rs
  15. 14 15
      tokens/token-2022/transfer-hook/allow-block-list-token/package.json
  16. 1 4
      tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-config.tsx
  17. 63 51
      tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-data-access.tsx
  18. 50 92
      tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-manage-token-detail.tsx
  19. 0 5
      tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-manage-token.tsx
  20. 1 1
      tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-new-token.tsx
  21. 4 22
      tokens/token-2022/transfer-hook/allow-block-list-token/src/components/account/account-data-access.tsx

+ 1 - 1
tokens/token-2022/transfer-hook/allow-block-list-token/.gitignore

@@ -41,4 +41,4 @@ yarn-error.log*
 next-env.d.ts
 
 # Anchor
-/anchor/target/
+/anchor/target/

+ 4 - 3
tokens/token-2022/transfer-hook/allow-block-list-token/README.md

@@ -9,6 +9,7 @@ The allow/block list is then consumed by a transfer-hook.
 
 The list is managed by a single authority and can be used by several token mints. This enables a separation of concerns between token management and allow/block list management, ideal for scenarios where an issuer wants a 3rd party managed allow/block list or wants to share the same list across a group of assets.
 
+
 Initializes new tokens with several configuration options:
 - Permanent delegate
 - Allow list
@@ -30,7 +31,7 @@ This repo includes a UI to manage the allow/block list based on the `legacy-next
 Install dependencies:
 `yarn install`
 
-Compile the program:
+Compile the program (make sure to replace your program ID):
 `anchor build`
 
 Compile the UI:
@@ -43,8 +44,8 @@ Serve the UI:
 
 There are a couple scripts to manage the local validator and deployment.
 
-To start the local validator and deploy the program:
+To start the local validator and deploy the program (uses the anchor CLI and default anchor keypair):
 `./scripts/start.sh`
 
 To stop the local validator:
-`./scripts/stop.sh`
+`./scripts/stop.sh`

+ 1 - 1
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/Anchor.toml

@@ -6,7 +6,7 @@ resolution = true
 skip-lint = false
 
 [programs.localnet]
-abl-token = "LtkoMwPSKxAE714EY3V1oAEQ5LciqJcRwQQuQnzEhQQ"
+abl-token = "EYBRvArz4kb5YLtzjD4TW6DbWhS8qjcMYqBU4wHLW3qj"
 
 [registry]
 url = "https://api.apr.dev"

+ 1 - 2
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/constants.rs

@@ -1,4 +1,3 @@
-
 pub const META_LIST_ACCOUNT_SEED: &[u8] = b"extra-account-metas";
 pub const CONFIG_SEED: &[u8] = b"config";
-pub const AB_WALLET_SEED: &[u8] = b"ab_wallet";
+pub const AB_WALLET_SEED: &[u8] = b"ab_wallet";

+ 1 - 1
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/errors.rs

@@ -13,4 +13,4 @@ pub enum ABListError {
 
     #[msg("Wallet blocked")]
     WalletBlocked,
-}
+}

+ 12 - 93
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/attach_to_mint.rs

@@ -1,27 +1,19 @@
-use anchor_lang::{prelude::*, solana_program::program::invoke, solana_program::system_instruction::transfer};
+use anchor_lang::prelude::*;
 use anchor_spl::{
-    token_2022::{spl_token_2022::{extension::{BaseStateWithExtensions, StateWithExtensions}, state::Mint as Mint2022}, Token2022},
-    token_interface::{spl_token_metadata_interface::state::{Field, TokenMetadata}, token_metadata_initialize, token_metadata_update_field, Mint, TokenMetadataInitialize, TokenMetadataUpdateField},
+    token_2022::Token2022,
+    token_interface::{transfer_hook_update, Mint, TransferHookUpdate},
 };
 
-use spl_tlv_account_resolution::{
-     state::ExtraAccountMetaList,
-};
+use spl_tlv_account_resolution::state::ExtraAccountMetaList;
 use spl_transfer_hook_interface::instruction::ExecuteInstruction;
 
-use crate::{Mode, META_LIST_ACCOUNT_SEED, get_extra_account_metas, get_meta_list_size};
-
+use crate::{get_extra_account_metas, get_meta_list_size, META_LIST_ACCOUNT_SEED};
 
 #[derive(Accounts)]
-#[instruction(args: AttachToMintArgs)]
 pub struct AttachToMint<'info> {
     #[account(mut)]
     pub payer: Signer<'info>,
 
-    pub mint_authority: Signer<'info>,
-
-    pub metadata_authority: Signer<'info>,
-
     #[account(
         mut,
         mint::token_program = token_program,
@@ -44,78 +36,16 @@ pub struct AttachToMint<'info> {
 }
 
 impl AttachToMint<'_> {
-    pub fn attach_to_mint(&mut self, args: AttachToMintArgs) -> Result<()> {
-        let mint_info = self.mint.to_account_info();
-        let mint_data = mint_info.data.borrow();
-        let mint = StateWithExtensions::<Mint2022>::unpack(&mint_data)?;
-
-        let metadata = mint.get_variable_len_extension::<TokenMetadata>();
-        
-        if metadata.is_err() {
-            // assume metadata is not initialized, so we need to initialize it
-    
-            let cpi_accounts = TokenMetadataInitialize {
-                program_id: self.token_program.to_account_info(),
-                mint: self.mint.to_account_info(),
-                metadata: self.mint.to_account_info(), // metadata account is the mint, since data is stored in mint
-                mint_authority: self.mint_authority.to_account_info(),
-                update_authority: self.metadata_authority.to_account_info(),
-            };
-            let cpi_ctx = CpiContext::new(
-                self.token_program.to_account_info(),
-                cpi_accounts,
-            );
-            token_metadata_initialize(cpi_ctx, args.name.unwrap(), args.symbol.unwrap(), args.uri.unwrap())?;
-        }
-
-        let cpi_accounts = TokenMetadataUpdateField {
-            metadata: self.mint.to_account_info(),
-            update_authority: self.metadata_authority.to_account_info(),
-            program_id: self.token_program.to_account_info(),
+    pub fn attach_to_mint(&mut self) -> Result<()> {
+        let tx_hook_accs = TransferHookUpdate {
+            token_program_id: self.token_program.to_account_info(),
+            mint: self.mint.to_account_info(),
+            authority: self.payer.to_account_info(),
         };
 
-        let cpi_ctx = CpiContext::new(
-            self.token_program.to_account_info(),
-            cpi_accounts,
-        );
+        let ctx = CpiContext::new(self.token_program.to_account_info(), tx_hook_accs);
 
-        token_metadata_update_field(cpi_ctx, Field::Key("AB".to_string()), args.mode.to_string())?;
-
-        if args.mode == Mode::Mixed {
-            let cpi_accounts = TokenMetadataUpdateField {
-                metadata: self.mint.to_account_info(),
-                update_authority: self.metadata_authority.to_account_info(),
-                program_id: self.token_program.to_account_info(),
-            };
-            let cpi_ctx = CpiContext::new(
-                self.token_program.to_account_info(),
-                cpi_accounts,
-            );
-
-            token_metadata_update_field(
-                cpi_ctx,
-                Field::Key("threshold".to_string()),
-                args.threshold.to_string(),
-            )?;
-        }
-
-        
-        let data = self.mint.to_account_info().data_len();
-        let min_balance = Rent::get()?.minimum_balance(data);
-        if min_balance > self.mint.to_account_info().get_lamports() {
-            invoke(
-                &transfer(
-                    &self.payer.key(),
-                    &self.mint.to_account_info().key(),
-                    min_balance - self.mint.to_account_info().get_lamports(),
-                ),
-                &[
-                    self.payer.to_account_info(),
-                    self.mint.to_account_info(),
-                    self.system_program.to_account_info(),
-                ],
-            )?;
-        }
+        transfer_hook_update(ctx, Some(crate::ID_CONST))?;
 
         // initialize the extra metas account
         let extra_metas_account = &self.extra_metas_account;
@@ -124,16 +54,5 @@ impl AttachToMint<'_> {
         ExtraAccountMetaList::init::<ExecuteInstruction>(&mut data, &metas)?;
 
         Ok(())
-        
     }
 }
-
-#[derive(AnchorSerialize, AnchorDeserialize)]
-pub struct AttachToMintArgs {
-    pub name: Option<String>,
-    pub symbol: Option<String>,
-    pub uri: Option<String>,
-    pub mode: Mode,
-    pub threshold: u64,
-}
-

+ 3 - 7
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/change_mode.rs

@@ -1,17 +1,15 @@
-use anchor_lang::{prelude::*, solana_program::system_instruction::transfer };
 use anchor_lang::solana_program::program::invoke;
+use anchor_lang::{prelude::*, solana_program::system_instruction::transfer};
 use anchor_spl::token_interface::spl_token_metadata_interface::state::TokenMetadata;
 use anchor_spl::{
     token_2022::{
         spl_token_2022::extension::{BaseStateWithExtensions, StateWithExtensions},
         spl_token_2022::state::Mint,
         Token2022,
-        
     },
     token_interface::{
-        Mint as MintAccount,
         spl_token_metadata_interface::state::Field, token_metadata_update_field,
-        TokenMetadataUpdateField,
+        Mint as MintAccount, TokenMetadataUpdateField,
     },
 };
 
@@ -21,7 +19,7 @@ use crate::Mode;
 pub struct ChangeMode<'info> {
     #[account(mut)]
     pub authority: Signer<'info>,
-    
+
     #[account(
         mut,
         mint::token_program = token_program,
@@ -73,8 +71,6 @@ impl ChangeMode<'_> {
             )?;
         }
 
-        
-
         let data = self.mint.to_account_info().data_len();
         let min_balance = Rent::get()?.minimum_balance(data);
         if min_balance > self.mint.to_account_info().get_lamports() {

+ 1 - 3
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/init_config.rs

@@ -1,6 +1,5 @@
-use anchor_lang::prelude::*;
 use crate::{Config, CONFIG_SEED};
-
+use anchor_lang::prelude::*;
 
 #[derive(Accounts)]
 pub struct InitConfig<'info> {
@@ -21,7 +20,6 @@ pub struct InitConfig<'info> {
 
 impl InitConfig<'_> {
     pub fn init_config(&mut self, config_bump: u8) -> Result<()> {
-
         self.config.set_inner(Config {
             authority: self.payer.key(),
             bump: config_bump,

+ 4 - 16
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/init_mint.rs

@@ -9,14 +9,11 @@ use anchor_spl::{
     },
 };
 
-use spl_tlv_account_resolution::
-    state::ExtraAccountMetaList
-;
+use spl_tlv_account_resolution::state::ExtraAccountMetaList;
 use spl_transfer_hook_interface::instruction::ExecuteInstruction;
 
 use crate::{get_extra_account_metas, get_meta_list_size, Mode, META_LIST_ACCOUNT_SEED};
 
-
 #[derive(Accounts)]
 #[instruction(args: InitMintArgs)]
 pub struct InitMint<'info> {
@@ -62,10 +59,7 @@ impl InitMint<'_> {
             mint_authority: self.payer.to_account_info(),
             update_authority: self.payer.to_account_info(),
         };
-        let cpi_ctx = CpiContext::new(
-            self.token_program.to_account_info(),
-            cpi_accounts,
-        );
+        let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts);
         token_metadata_initialize(cpi_ctx, args.name, args.symbol, args.uri)?;
 
         let cpi_accounts = TokenMetadataUpdateField {
@@ -74,10 +68,7 @@ impl InitMint<'_> {
             program_id: self.token_program.to_account_info(),
         };
 
-        let cpi_ctx = CpiContext::new(
-            self.token_program.to_account_info(),
-            cpi_accounts,
-        );
+        let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts);
 
         token_metadata_update_field(cpi_ctx, Field::Key("AB".to_string()), args.mode.to_string())?;
 
@@ -87,10 +78,7 @@ impl InitMint<'_> {
                 update_authority: self.payer.to_account_info(),
                 program_id: self.token_program.to_account_info(),
             };
-            let cpi_ctx = CpiContext::new(
-                self.token_program.to_account_info(),
-                cpi_accounts,
-            );
+            let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts);
 
             token_metadata_update_field(
                 cpi_ctx,

+ 8 - 9
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/mod.rs

@@ -1,16 +1,15 @@
+pub mod attach_to_mint;
+pub mod change_mode;
+pub mod init_config;
 pub mod init_mint;
 pub mod init_wallet;
-pub mod tx_hook;
 pub mod remove_wallet;
-pub mod change_mode;
-pub mod init_config;
-pub mod attach_to_mint;
+pub mod tx_hook;
 
+pub use attach_to_mint::*;
+pub use change_mode::*;
+pub use init_config::*;
 pub use init_mint::*;
 pub use init_wallet::*;
-pub use tx_hook::*;
 pub use remove_wallet::*;
-pub use change_mode::*;
-pub use init_config::*;
-pub use attach_to_mint::*;
-
+pub use tx_hook::*;

+ 5 - 5
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/lib.rs

@@ -2,18 +2,18 @@ use anchor_lang::prelude::*;
 use spl_discriminator::SplDiscriminate;
 use spl_transfer_hook_interface::instruction::ExecuteInstruction;
 
+pub mod constants;
 pub mod errors;
 pub mod instructions;
 pub mod state;
-pub mod constants;
 pub mod utils;
+pub use constants::*;
 pub use errors::*;
 pub use instructions::*;
 pub use state::*;
-pub use constants::*;
 pub use utils::*;
 
-declare_id!("LtkoMwPSKxAE714EY3V1oAEQ5LciqJcRwQQuQnzEhQQ");
+declare_id!("3ku1ZEGvBEEfhaYsAzBZuecTPEa58ZRhoVqHVGpGxVGi");
 
 #[program]
 pub mod abl_token {
@@ -28,8 +28,8 @@ pub mod abl_token {
         ctx.accounts.init_config(ctx.bumps.config)
     }
 
-    pub fn attach_to_mint(ctx: Context<AttachToMint>, args: AttachToMintArgs) -> Result<()> {
-        ctx.accounts.attach_to_mint(args)
+    pub fn attach_to_mint(ctx: Context<AttachToMint>) -> Result<()> {
+        ctx.accounts.attach_to_mint()
     }
 
     #[instruction(discriminator = ExecuteInstruction::SPL_DISCRIMINATOR_SLICE)]

+ 5 - 3
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/state.rs

@@ -1,4 +1,7 @@
-use std::{fmt::{self, Display}, str::FromStr};
+use std::{
+    fmt::{self, Display},
+    str::FromStr,
+};
 
 use anchor_lang::prelude::*;
 
@@ -20,7 +23,7 @@ pub struct Config {
 pub enum Mode {
     Allow,
     Block,
-    Mixed
+    Mixed,
 }
 
 impl FromStr for Mode {
@@ -45,4 +48,3 @@ impl Display for Mode {
         }
     }
 }
-

+ 0 - 3
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/utils.rs

@@ -6,9 +6,6 @@ use spl_tlv_account_resolution::{
 
 use crate::AB_WALLET_SEED;
 
-
-
-
 pub fn get_meta_list_size() -> Result<usize> {
     Ok(ExtraAccountMetaList::size_of(1).unwrap())
 }

+ 17 - 14
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/tests/test.rs

@@ -1,6 +1,18 @@
 use {
-    anchor_lang::ToAccountMetas, anchor_lang::InstructionData, solana_message::Message,
-    abl_token::{accounts::InitMint, accounts::InitConfig, instructions::InitMintArgs, Mode}, litesvm::LiteSVM, solana_instruction::Instruction, solana_keypair::Keypair, solana_native_token::LAMPORTS_PER_SOL, solana_pubkey::{pubkey, Pubkey}, solana_sdk_ids::system_program::ID as SYSTEM_PROGRAM_ID, solana_signer::Signer, solana_transaction::Transaction, spl_token_2022::ID as TOKEN_22_PROGRAM_ID, std::path::PathBuf
+    abl_token::{accounts::InitConfig, accounts::InitMint, instructions::InitMintArgs, Mode},
+    anchor_lang::InstructionData,
+    anchor_lang::ToAccountMetas,
+    litesvm::LiteSVM,
+    solana_instruction::Instruction,
+    solana_keypair::Keypair,
+    solana_message::Message,
+    solana_native_token::LAMPORTS_PER_SOL,
+    solana_pubkey::{pubkey, Pubkey},
+    solana_sdk_ids::system_program::ID as SYSTEM_PROGRAM_ID,
+    solana_signer::Signer,
+    solana_transaction::Transaction,
+    spl_token_2022::ID as TOKEN_22_PROGRAM_ID,
+    std::path::PathBuf,
 };
 
 const PROGRAM_ID: Pubkey = abl_token::ID_CONST;
@@ -12,12 +24,11 @@ fn setup() -> (LiteSVM, Keypair) {
 
     svm.airdrop(&admin_pk, 10000 * LAMPORTS_PER_SOL).unwrap();
 
-
     let mut so_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     so_path.push("../../target/deploy/abl_token.so");
 
     println!("Deploying program from {}", so_path.display());
-    
+
     let bytecode = std::fs::read(so_path).unwrap();
 
     svm.add_program(PROGRAM_ID, &bytecode);
@@ -27,7 +38,6 @@ fn setup() -> (LiteSVM, Keypair) {
 
 #[test]
 fn test() {
-
     let (mut svm, admin_kp) = setup();
     let admin_pk = admin_kp.pubkey();
 
@@ -36,7 +46,7 @@ fn test() {
     let config = derive_config();
     let meta_list = derive_meta_list(&mint_pk);
 
-    let init_cfg_ix = abl_token::instruction::InitConfig {   };
+    let init_cfg_ix = abl_token::instruction::InitConfig {};
 
     let init_cfg_accounts = InitConfig {
         payer: admin_pk,
@@ -68,9 +78,7 @@ fn test() {
         mode: Mode::Mixed,
         threshold: 100000,
     };
-    let init_mint_ix = abl_token::instruction::InitMint {
-        args: args,
-    };
+    let init_mint_ix = abl_token::instruction::InitMint { args: args };
 
     let data = init_mint_ix.data();
 
@@ -93,9 +101,6 @@ fn test() {
     let tx = Transaction::new(&[&admin_kp, &mint_kp], msg, svm.latest_blockhash());
 
     let _res = svm.send_transaction(tx).unwrap();
-
-    
-
 }
 
 fn derive_config() -> Pubkey {
@@ -107,5 +112,3 @@ fn derive_meta_list(mint: &Pubkey) -> Pubkey {
     let seeds = &[b"extra-account-metas", mint.as_ref()];
     Pubkey::find_program_address(seeds, &PROGRAM_ID).0
 }
-
-

+ 14 - 15
tokens/token-2022/transfer-hook/allow-block-list-token/package.json

@@ -17,28 +17,27 @@
   },
   "dependencies": {
     "@coral-xyz/anchor": "^0.31.1",
-    "@radix-ui/react-dialog": "^1.1.11",
-    "@radix-ui/react-dropdown-menu": "^2.1.12",
-    "@radix-ui/react-label": "^2.1.4",
-    "@radix-ui/react-slot": "^1.2.0",
+    "@radix-ui/react-dialog": "^1.1.14",
+    "@radix-ui/react-dropdown-menu": "^2.1.15",
+    "@radix-ui/react-label": "^2.1.7",
+    "@radix-ui/react-slot": "^1.2.3",
     "@solana/spl-token": "0.4.13",
-    "@solana/wallet-adapter-base": "0.9.26",
-    "@solana/wallet-adapter-react": "0.15.38",
-    "@solana/wallet-adapter-react-ui": "0.9.38",
+    "@solana/wallet-adapter-base": "0.9.27",
+    "@solana/wallet-adapter-react": "0.15.39",
+    "@solana/wallet-adapter-react-ui": "0.9.39",
     "@solana/web3.js": "1.98.2",
-    "@tanstack/react-query": "^5.74.7",
-    "bigint-buffer": "^1.1.5",
+    "@tanstack/react-query": "^5.82.0",
     "class-variance-authority": "^0.7.1",
     "clsx": "^2.1.1",
-    "jotai": "^2.12.3",
-    "lucide-react": "^0.503.0",
-    "next": "15.3.1",
+    "jotai": "^2.12.5",
+    "lucide-react": "^0.525.0",
+    "next": "15.3.5",
     "next-themes": "^0.4.6",
     "react": "^19.1.0",
     "react-dom": "^19.1.0",
-    "sonner": "^2.0.3",
-    "tailwind-merge": "^3.2.0",
-    "tw-animate-css": "^1.2.8"
+    "sonner": "^2.0.6",
+    "tailwind-merge": "^3.3.1",
+    "tw-animate-css": "^1.3.5"
   },
   "devDependencies": {
     "@eslint/eslintrc": "^3.3.1",

+ 1 - 4
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-config.tsx

@@ -4,7 +4,6 @@ import { useWallet } from '@solana/wallet-adapter-react'
 import { ExplorerLink } from '../cluster/cluster-ui'
 import { WalletButton } from '../solana/solana-provider'
 import { useAblTokenProgram } from './abl-token-data-access'
-import { AblTokenCreate, AblTokenProgram } from './abl-token-ui'
 import { AppHero } from '../app-hero'
 import { ellipsify } from '@/lib/utils'
 import { Button } from '@/components/ui/button'
@@ -14,7 +13,6 @@ import { PublicKey } from '@solana/web3.js'
 export default function AblTokenConfig() {
   const { publicKey } = useWallet()
   const { programId, getConfig, getAbWallets } = useAblTokenProgram()
-  const [lastUpdate, setLastUpdate] = React.useState(0)
 
   const config = getConfig.data;
   let abWallets = getAbWallets.data;
@@ -22,7 +20,6 @@ export default function AblTokenConfig() {
   const handleWalletListUpdate = React.useCallback(async () => {
     await getAbWallets.refetch();
     abWallets = getAbWallets.data;
-    setLastUpdate(Date.now())
   }, [])
 
   return publicKey ? (
@@ -94,7 +91,7 @@ export function AblTokenConfigCreate() {
   );
 }
 
-export function AblTokenConfigList({ abWallets }: { abWallets: any[] | undefined }) {
+export function AblTokenConfigList({ abWallets }: { abWallets: {publicKey: PublicKey, account: {wallet: PublicKey, allowed: boolean}}[] | undefined }) {
   return (
     <div className="space-y-4">
       <h2 className="text-2xl font-bold">ABL Token Config List</h2>

+ 63 - 51
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-data-access.tsx

@@ -10,15 +10,13 @@ import { useAnchorProvider } from '../solana/solana-provider'
 import { useTransactionToast } from '../use-transaction-toast'
 import { toast } from 'sonner'
 import { BN } from '@coral-xyz/anchor'
-import { amountToUiAmount, createAssociatedTokenAccountIdempotentInstruction, createAssociatedTokenAccountIdempotentInstructionWithDerivation, createMintToCheckedInstruction, decodeMintToCheckedInstruction, getAssociatedTokenAddressSync, getMint, getPermanentDelegate, getTokenMetadata, getTransferHook, mintToChecked, mintToCheckedInstructionData, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token'
-
+import { createAssociatedTokenAccountIdempotentInstruction, createMintToCheckedInstruction, getAssociatedTokenAddressSync, getMint, getPermanentDelegate, getTokenMetadata, getTransferHook, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token'
 
 export function useHasTransferHookEnabled(mint: PublicKey) {
   const { connection } = useConnection()
-  const provider = useAnchorProvider()
   const { cluster } = useCluster()
   const programId = useMemo(() => getABLTokenProgramId(cluster.network as Cluster), [cluster])
-  const program = useMemo(() => getABLTokenProgram(provider, programId), [provider, programId])
+
   return useQuery({
     queryKey: ['has-transfer-hook', { cluster }],
     queryFn: async () => {
@@ -33,6 +31,60 @@ export function useHasTransferHookEnabled(mint: PublicKey) {
     },
   })
 }
+
+export function useGetToken(mint: PublicKey) {
+  const { connection } = useConnection()
+  const { cluster } = useCluster()
+  const programId = useMemo(() => getABLTokenProgramId(cluster.network as Cluster), [cluster])
+
+  return useQuery({
+  queryKey: ['get-token', { endpoint: connection.rpcEndpoint, mint }],
+  queryFn: async () => {
+    const mintInfo = await getMint(
+      connection,
+      mint,
+      "confirmed",
+      TOKEN_2022_PROGRAM_ID,
+    );
+
+    const metadata = await getTokenMetadata(
+      connection,
+      mint,
+      "confirmed",
+      TOKEN_2022_PROGRAM_ID,
+    );
+
+    const mode = metadata?.additionalMetadata.find((metadata) => metadata[0] === "AB")?.[1] || null;
+    const threshold = metadata?.additionalMetadata.find((metadata) => metadata[0] === "threshold")?.[1] || null;
+
+    const permanentDelegate = await getPermanentDelegate(mintInfo);
+
+    const transferHook = getTransferHook(mintInfo);
+
+    const isTransferHookEnabled = transferHook !== null;
+    const isTransferHookSet = transferHook?.programId?.equals(programId) || false;
+    const transferHookProgramId = transferHook?.programId || null;
+
+    return {
+      name: metadata?.name,
+      symbol: metadata?.symbol,
+      uri: metadata?.uri,
+      decimals: mintInfo.decimals,
+      supply: mintInfo.supply,
+      mintAuthority: mintInfo.mintAuthority,
+      freezeAuthority: mintInfo.freezeAuthority,
+      permanentDelegate: permanentDelegate?.delegate ?? null,
+      isTransferHookEnabled,
+      isTransferHookSet,
+      transferHookProgramId,
+      mode,
+      threshold,
+    }
+  },
+})
+}
+
+
 export function useAblTokenProgram() {
   const { connection } = useConnection()
   const { cluster } = useCluster()
@@ -89,21 +141,8 @@ export function useAblTokenProgram() {
     mutationKey: ['abl-token', 'attach-to-existing-token', { cluster }],
     mutationFn: (args: {
       mint: PublicKey,
-      mode: string,
-      threshold: BN,
-      name: string | null,
-      symbol: string | null,
-      uri: string | null,
     }) => {
-      const modeEnum = args.mode === 'allow' ? { allow: {} } : args.mode === 'block' ? { block: {}} : { mixed: {}};
-
-      return program.methods.attachToMint({
-        mode: modeEnum,
-        threshold: args.threshold,
-        name: args.name,
-        symbol: args.symbol,
-        uri: args.uri,
-      }).accounts({
+      return program.methods.attachToMint().accounts({
         mint: args.mint,
       }).rpc()
     },
@@ -120,7 +159,7 @@ export function useAblTokenProgram() {
       threshold: BN,
       mint: PublicKey,
     }) => {
-      const modeEnum = args.mode === 'allow' ? { allow: {} } : args.mode === 'block' ? { block: {}} : { mixed: {}}
+      const modeEnum = args.mode === 'Allow' ? { allow: {} } : args.mode === 'Block' ? { block: {}} : { mixed: {}}
       return program.methods.changeMode({
         mode: modeEnum,
         threshold: args.threshold,
@@ -183,7 +222,7 @@ export function useAblTokenProgram() {
       transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
       //transaction.sign(provider.wallet);
 
-      let signedTx = await provider.wallet.signTransaction(transaction);
+      const  signedTx = await provider.wallet.signTransaction(transaction);
 
       return connection.sendRawTransaction(signedTx.serialize());
 
@@ -243,36 +282,8 @@ export function useAblTokenProgram() {
     },
   })
 
-  const getToken = (mint: PublicKey) => useQuery({
-    queryKey: ['get-token', { endpoint: connection.rpcEndpoint, mint }],
-    queryFn: async () => {
-      const mintInfo = await getMint(
-        connection,
-        mint,
-        "confirmed",
-        TOKEN_2022_PROGRAM_ID,
-      );
 
-      const metadata = await getTokenMetadata(
-        connection,
-        mint,
-        "confirmed",
-        TOKEN_2022_PROGRAM_ID,
-      );
-
-      const permanentDelegate = await getPermanentDelegate(mintInfo);
-
-      return {
-        name: metadata?.name,
-        symbol: metadata?.symbol,
-        uri: metadata?.uri,
-        decimals: mintInfo.decimals,
-        mintAuthority: mintInfo.mintAuthority,
-        freezeAuthority: mintInfo.freezeAuthority,
-        permanentDelegate: permanentDelegate,
-      }
-    },
-  })
+  
 /*
   const getBalance = useQuery({
     queryKey: ['get-balance', { cluster }],
@@ -302,7 +313,7 @@ export function useAblTokenProgram() {
       tx.add(ix, ix2);
       tx.feePayer = provider.wallet.publicKey;
       tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
-      let signedTx = await provider.wallet.signTransaction(tx);
+      const  signedTx = await provider.wallet.signTransaction(tx);
       return connection.sendRawTransaction(signedTx.serialize())
     },
     onSuccess: (signature) => {
@@ -311,6 +322,7 @@ export function useAblTokenProgram() {
     onError: () => toast.error('Failed to run program'),
   })
 
+
   return {
     program,
     programId,
@@ -322,9 +334,9 @@ export function useAblTokenProgram() {
     initConfig,
     getConfig,
     getAbWallets,
-    getToken,
     processBatchWallets,
     mintTo,
     attachToExistingToken,
   }
 }
+

+ 50 - 92
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-manage-token-detail.tsx

@@ -4,9 +4,8 @@ import { useWallet } from '@solana/wallet-adapter-react'
 import { WalletButton } from '../solana/solana-provider'
 import { useParams } from 'next/navigation'
 import React from 'react'
-import { useAblTokenProgram, useHasTransferHookEnabled } from './abl-token-data-access'
+import { useAblTokenProgram, useGetToken } from './abl-token-data-access'
 import { PublicKey } from '@solana/web3.js'
-import { PermanentDelegate } from '@solana/spl-token'
 import { BN } from '@coral-xyz/anchor'
 import { Button } from '@/components/ui/button'
 
@@ -19,24 +18,44 @@ interface TokenInfo {
   supply: number;
   mintAuthority: PublicKey | null;
   freezeAuthority: PublicKey | null;
-  permanentDelegate: PermanentDelegate | null;
+  permanentDelegate: PublicKey | null;
+  mode: string | null;
+  threshold: string | null;
+  transferHookProgramId: PublicKey | null;
+  isTransferHookEnabled: boolean;
+  isTransferHookSet: boolean;
 }
 
-function TokenInfo({ tokenInfo }: { tokenInfo: TokenInfo | null }) {
+function TokenInfo({ tokenAddress }: { tokenAddress: string }) {
+  const { attachToExistingToken } = useAblTokenProgram()
+  const tokenInfo = useGetToken(new PublicKey(tokenAddress));
   return (
     <div className="bg-base-200 p-6 rounded-lg">
       <h2 className="text-2xl font-bold mb-4">Token Information</h2>
       {tokenInfo ? (
         <div className="grid grid-cols-2 gap-4">
-          <div>Address: {tokenInfo.address}</div>
-          <div>Name: {tokenInfo.name}</div>
-          <div>Symbol: {tokenInfo.symbol}</div>
-          <div>Decimals: {tokenInfo.decimals}</div>
-          <div>URI: {tokenInfo.uri}</div>
-          <div>Supply: {tokenInfo.supply}</div>
-          <div>Mint Authority: {tokenInfo.mintAuthority?.toString()}</div>
-          <div>Freeze Authority: {tokenInfo.freezeAuthority?.toString()}</div>
-          <div>Permanent Delegate: {tokenInfo.permanentDelegate?.delegate.toString()}</div>
+          <div>Address: {tokenAddress}</div>
+          <div>Name: {tokenInfo.data?.name}</div>
+          <div>Symbol: {tokenInfo.data?.symbol}</div>
+          <div>Decimals: {tokenInfo.data?.decimals}</div>
+          <div>URI: {tokenInfo.data?.uri}</div>
+          <div>Supply: {tokenInfo.data?.supply}</div>
+          <div>Mint Authority: {tokenInfo.data?.mintAuthority?.toString()}</div>
+          <div>Freeze Authority: {tokenInfo.data?.freezeAuthority?.toString()}</div>
+          <div>Permanent Delegate: {tokenInfo.data?.permanentDelegate?.toString()}</div>
+          <br/>
+          <div>
+            <h3 className="text-xl font-bold mb-2">ABL Token</h3>
+            <div>Mode: {tokenInfo.data?.mode}</div>
+            <div>Threshold: {tokenInfo.data?.threshold?.toString()}</div>
+            {tokenInfo.data?.isTransferHookEnabled ? (tokenInfo.data?.isTransferHookSet ? (
+              <div>TxHook: Enabled and Set ✅</div>
+            ) : (
+              <div>TxHook: Enabled. <Button onClick={() => attachToExistingToken.mutateAsync({ mint: new PublicKey(tokenAddress) }).then()}>Set</Button></div>
+            )) : (
+              <div>TxHook: Not enabled ❌</div>
+            )}
+          </div>
         </div>
       ) : (
         <p>No token information available.</p>
@@ -47,15 +66,10 @@ function TokenInfo({ tokenInfo }: { tokenInfo: TokenInfo | null }) {
 
 function TokenManagement({ tokenInfo }: { tokenInfo: TokenInfo }) {
   const { publicKey } = useWallet()
-  const { changeMode, mintTo, attachToExistingToken } = useAblTokenProgram()
-  const [mode, setMode] = React.useState<'allow' | 'block' | 'mixed'>('allow')
-  const [threshold, setThreshold] = React.useState('100000')
+  const { changeMode, mintTo } = useAblTokenProgram()
+  const [mode, setMode] = React.useState<'Allow' | 'Block' | 'Mixed'>(tokenInfo.mode as 'Allow' | 'Block' | 'Mixed')
+  const [threshold, setThreshold] = React.useState<string | undefined>(tokenInfo.threshold ?? undefined)
   const [destinationWallet, setDestinationWallet] = React.useState('')
-  const hasTransferHookEnabled = useHasTransferHookEnabled(new PublicKey(tokenInfo.address))
-  const [name, setName] = React.useState<string>('')
-  const [symbol, setSymbol] = React.useState<string>('')
-  const [uri, setUri] = React.useState<string>('')
-
 
   const handleApplyChanges = async () => {
     if (!publicKey || !tokenInfo) return;
@@ -63,7 +77,7 @@ function TokenManagement({ tokenInfo }: { tokenInfo: TokenInfo }) {
     try {
       await changeMode.mutateAsync({
         mode,
-        threshold: new BN(threshold),
+        threshold: threshold === undefined ? new BN(0) : new BN(threshold),
         mint: new PublicKey(tokenInfo.address),
       });
     } catch (err) {
@@ -71,23 +85,6 @@ function TokenManagement({ tokenInfo }: { tokenInfo: TokenInfo }) {
     }
   };
 
-  const setTransferHook = async () => {
-    if (!publicKey || !tokenInfo) return;
-
-    try {
-      await attachToExistingToken.mutateAsync({
-        mint: new PublicKey(tokenInfo.address),
-        mode,
-        threshold: new BN(threshold),
-        name,
-        symbol,
-        uri,
-      });
-    } catch (err) {
-      console.error('Failed to set transfer hook:', err);
-    }
-  };
-
   const [mintAmount, setMintAmount] = React.useState('0')
 
   const handleMint = async () => {
@@ -110,37 +107,37 @@ function TokenManagement({ tokenInfo }: { tokenInfo: TokenInfo }) {
       <h2 className="text-2xl font-bold mb-4">Token Management</h2>
       <div className="space-y-4">
         <div>
-          {hasTransferHookEnabled.data ? (
+          {tokenInfo.isTransferHookSet && (
             <div>
               <label className="block mb-2">Mode</label>
               <div className="flex gap-4">
                 <label>
                   <input
                     type="radio"
-                    checked={mode === 'allow'}
-                    onChange={() => setMode('allow')}
+                    checked={mode === 'Allow'}
+                    onChange={() => {setMode('Allow'); setThreshold(tokenInfo.threshold ?? undefined);}}
                     name="mode"
                   /> Allow
                 </label>
                 <label>
                   <input
                     type="radio"
-                    checked={mode === 'block'}
-                    onChange={() => setMode('block')}
+                    checked={mode === 'Block'}
+                    onChange={() => {setMode('Block'); setThreshold(tokenInfo.threshold ?? undefined);}}
                     name="mode"
                   /> Block
                 </label>
                 <label>
                   <input
                     type="radio"
-                    checked={mode === 'mixed'}
-                    onChange={() => setMode('mixed')}
+                    checked={mode === 'Mixed'}
+                    onChange={() => setMode('Mixed')}
                     name="mode"
                   /> Mixed
                 </label>
               </div>
 
-              {mode === 'mixed' && (
+              {mode === 'Mixed' && (
               <div>
                 <label className="block mb-2">Threshold Amount</label>
                 <input
@@ -154,52 +151,15 @@ function TokenManagement({ tokenInfo }: { tokenInfo: TokenInfo }) {
               )}
 
               <div className="mt-4">
-                <Button onClick={handleApplyChanges}>
+                <Button 
+                  onClick={handleApplyChanges}
+                  disabled={mode === tokenInfo.mode && (threshold === tokenInfo.threshold || (threshold === undefined && tokenInfo.threshold === null))}
+                >
                   Apply Changes
                 </Button>
               </div>
               
             </div>
-          ) : (
-            <div>
-            <div className="space-y-4">
-              <div>
-                <label className="block mb-2">Name (Optional)</label>
-                <input
-                  type="text"
-                  className="w-full p-2 border rounded"
-                  value={name}
-                  onChange={e => setName(e.target.value)}
-                  placeholder="Enter token name"
-                />
-              </div>
-              <div>
-                <label className="block mb-2">Symbol (Optional)</label>
-                <input
-                  type="text"
-                  className="w-full p-2 border rounded"
-                  value={symbol}
-                  onChange={e => setSymbol(e.target.value)}
-                  placeholder="Enter token symbol"
-                />
-              </div>
-              <div>
-                <label className="block mb-2">URI (Optional)</label>
-                <input
-                  type="text"
-                  className="w-full p-2 border rounded"
-                  value={uri}
-                  onChange={e => setUri(e.target.value)}
-                  placeholder="Enter token URI"
-                />
-              </div>
-            </div>
-            <div className="mt-4">
-              <Button onClick={setTransferHook}>
-                Set Transfer hook
-              </Button>
-            </div>
-            </div>
           )}
         </div>
 
@@ -238,11 +198,9 @@ function TokenManagement({ tokenInfo }: { tokenInfo: TokenInfo }) {
 
 export default function ManageTokenDetail() {
   const { publicKey } = useWallet()
-  const { getToken } = useAblTokenProgram()
   const params = useParams()
   const tokenAddress = params?.address as string
-
-  const tokenQuery = getToken(new PublicKey(tokenAddress));
+  const tokenQuery = useGetToken(new PublicKey(tokenAddress));
 
   const tokenInfo = React.useMemo(() => {
     if (!tokenQuery?.data || !tokenAddress) return null;
@@ -271,7 +229,7 @@ export default function ManageTokenDetail() {
         <p>Error loading token information. Please check the token address.</p>
       ) : (
         <>
-          <TokenInfo tokenInfo={tokenInfo} />
+          <TokenInfo tokenAddress={tokenAddress} />
           {tokenInfo && <TokenManagement tokenInfo={tokenInfo}/>}
           
         </>

+ 0 - 5
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-manage-token.tsx

@@ -1,16 +1,11 @@
 'use client'
 
 import { useWallet } from '@solana/wallet-adapter-react'
-import { ExplorerLink } from '../cluster/cluster-ui'
 import { WalletButton } from '../solana/solana-provider'
-import { useAblTokenProgram } from './abl-token-data-access'
-import { AblTokenCreate, AblTokenProgram } from './abl-token-ui'
 import { AppHero } from '../app-hero'
-import { ellipsify } from '@/lib/utils'
 import ManageTokenInput from './abl-token-manage-token-input'
 export default function AblTokenFeature() {
   const { publicKey } = useWallet()
-  const { programId } = useAblTokenProgram()
 
   return publicKey ? (
     <div>

+ 1 - 1
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-new-token.tsx

@@ -4,7 +4,7 @@ import { useWallet } from '@solana/wallet-adapter-react'
 import { ExplorerLink } from '../cluster/cluster-ui'
 import { WalletButton } from '../solana/solana-provider'
 import { useAblTokenProgram } from './abl-token-data-access'
-import { AblTokenCreate, AblTokenProgram } from './abl-token-ui'
+import { AblTokenCreate } from './abl-token-ui'
 import { AppHero } from '../app-hero'
 import { ellipsify } from '@/lib/utils'
 

+ 4 - 22
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/account/account-data-access.tsx

@@ -1,12 +1,11 @@
 'use client'
 
-import { createAssociatedTokenAccountIdempotentInstruction, createTransferCheckedInstruction, createTransferCheckedWithTransferHookInstruction, getAssociatedTokenAddressSync, getExtraAccountMetaAddress, getExtraAccountMetas, getMint, getTransferHook, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token'
+import { createAssociatedTokenAccountIdempotentInstruction, createTransferCheckedInstruction, getAssociatedTokenAddressSync, getExtraAccountMetaAddress, getMint, getTransferHook, TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token'
 import { useConnection, useWallet } from '@solana/wallet-adapter-react'
 import {
   Connection,
   LAMPORTS_PER_SOL,
   PublicKey,
-  SendTransactionError,
   SystemProgram,
   Transaction,
   TransactionMessage,
@@ -16,7 +15,6 @@ import {
 import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
 import { useTransactionErrorToast, useTransactionToast } from '../use-transaction-toast'
 import { useAnchorProvider } from '../solana/solana-provider'
-import { toast } from 'sonner'
 import { Buffer } from "buffer"
 
 export function useGetBalance({ address }: { address: PublicKey }) {
@@ -58,14 +56,7 @@ export function useSendTokens() {
       const ix = createAssociatedTokenAccountIdempotentInstruction(publicKey, ataDestination, destination, mint, TOKEN_2022_PROGRAM_ID);
       const bi = BigInt(amount);
       const decimals = mintInfo.decimals;
-      console.log("BI: ", bi);
-      console.log("AMOUNT: ", amount);
-      console.log("DECIMALS: ", decimals);
-      const buf = Buffer.alloc(10);
-      console.dir(buf);
-  
-      buf.writeBigUInt64LE(bi, 0);
-      console.log(buf);
+
       const ix3 = await createTransferCheckedInstruction(ataSource, mint, ataDestination, publicKey, bi, decimals, undefined, TOKEN_2022_PROGRAM_ID);
 
       const transferHook = getTransferHook(mintInfo);
@@ -78,25 +69,16 @@ export function useSendTokens() {
       ix3.keys.push({ pubkey: abWallet, isSigner: false, isWritable: false });
       ix3.keys.push({ pubkey: transferHook.programId, isSigner: false, isWritable: false });
       ix3.keys.push({ pubkey: extraMetas, isSigner: false, isWritable: false });
-
-      console.log("tx-hook: ", transferHook.programId.toString());
-      console.log("extra-metas: ", extraMetas.toString());
-      console.log("ab-wallet: ", abWallet.toString());
-      console.log("KEYS: ", ix3.keys);
       
       const validateStateAccount = await connection.getAccountInfo(extraMetas, 'confirmed');
       if (!validateStateAccount) throw new Error('validate-state-account not found');
-      const validateStateData = getExtraAccountMetas(validateStateAccount);
-      console.log("validate-state-data: ", validateStateData);
-    
-      //const ix2 = await createTransferCheckedWithTransferHookInstruction(connection, ataSource, mint, ataDestination, publicKey, bi, decimals, undefined, 'confirmed', TOKEN_2022_PROGRAM_ID);
-      
+
       const transaction = new Transaction();
       transaction.add(ix, ix3);
       transaction.feePayer = provider.wallet.publicKey;
       transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
 
-      let signedTx = await provider.wallet.signTransaction(transaction);
+      const signedTx = await provider.wallet.signTransaction(transaction);
 
       return connection.sendRawTransaction(signedTx.serialize());
     },