Sol.College

Full lesson

alexwu0209-ALLOY

ALLOY: Tokenizing Private Credit on Solana

What it does

From the project README:

Developed by the Alloy team (@alloyRWA) - Pioneering Real World Asset Tokenization on Solana
Original
alexwu0209/ALLOY
SuperStack fork
Blockchains/alexwu0209-ALLOY @ e33c954
Stars
1
Last push (original)
2025-05-15
Languages
TypeScript, Rust, JavaScript
Detected stack
Anchorweb3.js
Categories
Other
Licence
MIT

Architecture

57 source files. By extension: .ts ×33, .rs ×19, .js ×3, .tsx ×2.

Top-level directorySource files
sdk32
programs19
tests6

On-chain programs: programs/alloy-tokenization, programs/alloy-transfer-hook

Dapp: devnet deploy pending

⏳ Devnet deploy pending — goes live when the devnet wallet is topped up. This fork's own dapp is not deployed yet, so there is no program address or transaction to show. It is queued in dapp-queue.txt; once devnet SOL is available it is deployed, exercised with real devnet transactions, and this section switches to the live dapp at /dapps/alexwu0209-alloy/. Until then, the lesson and step-by-step guide below are complete, and you can run it locally with the commands below.

Key code, explained

Excerpts chosen automatically where the code uses the most Solana concepts, pinned to the fork's commit.

alexwu0209/ALLOY · programs/alloy-tokenization/src/instructions/create_asset.rs L13–35 @ e33c954 · MIT · original
pub struct CreateTokenizedAsset<'info> {    #[account(mut)]    pub payer: Signer<'info>,        /// The authority that will be set as mint authority    pub mint_authority: Signer<'info>,        /// The authority that will be set as freeze authority    pub freeze_authority: Signer<'info>,        /// The mint account to be created    #[account(mut)]    pub mint: Signer<'info>,        /// Asset metadata account    #[account(        init,        payer = payer,        space = 8 + std::mem::size_of::<AssetMetadata>() + 1024, // Extra space for vectors        seeds = [b"metadata", mint.key().as_ref()],        bump    )]    pub asset_metadata: Account<'info, AssetMetadata>,
  1. Line 15 pub payer: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 29 init,: Creates and pays for a new account. Space and payer must be specified.
  3. Line 32 seeds = [b"metadata", mint.key().as_ref()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  4. Line 33 bump: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
alexwu0209/ALLOY · programs/alloy-tokenization/src/instructions/confidential.rs L13–36 @ e33c954 · MIT · original
use solana_program::program::invoke_signed; use crate::{state::*, errors::ErrorCode}; #[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]pub struct ConfidentialTransferConfig {    pub auto_approve_new_accounts: bool,    pub auditor_encryption_key: Option<[u8; 32]>,} #[derive(Accounts)]pub struct EnableConfidentialTransfers<'info> {    #[account(mut)]    pub authority: Signer<'info>,        #[account(mut)]    pub mint: Account<'info, Mint>,        #[account(        mut,        seeds = [b"metadata", mint.key().as_ref()],        bump,    )]    pub asset_metadata: Account<'info, AssetMetadata>,
  1. Line 13 use solana_program::program::invoke_signed;: Makes a CPI signed by a PDA. The signer seeds prove the program controls that address.
  2. Line 26 pub authority: Signer<'info>,: Requires this account to have signed the transaction.
  3. Line 33 seeds = [b"metadata", mint.key().as_ref()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  4. Line 34 bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
alexwu0209/ALLOY · programs/alloy-tokenization/src/state/pause.rs L1–24 @ e33c954 · MIT · original
use anchor_lang::prelude::*;use crate::errors::ErrorCode; #[account]pub struct PauseState {    pub mint: Pubkey,    pub paused: bool,    pub paused_by: Option<Pubkey>,    pub paused_at: Option<i64>,    pub bump: u8,} impl PauseState {    pub fn check_not_paused(&self) -> Result<()> {        if self.paused {            return err!(ErrorCode::ContractPaused);        }        Ok(())    }        pub fn pause(&mut self, authority: Pubkey) -> Result<()> {        self.paused = true;        self.paused_by = Some(authority);        self.paused_at = Some(Clock::get()?.unix_timestamp);
  1. Line 10 pub bump: u8,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
  2. Line 16 return err!(ErrorCode::ContractPaused);: An explicit validation that aborts the instruction with an error.
  3. Line 24 self.paused_at = Some(Clock::get()?.unix_timestamp);: Reads on-chain time from the Clock sysvar.
alexwu0209/ALLOY · programs/alloy-tokenization/src/instructions/payments.rs L1–24 @ e33c954 · MIT · original
use anchor_lang::prelude::*;use crate::{state::*, errors::ErrorCode}; #[derive(Accounts)]pub struct DistributePayment<'info> {    #[account(mut)]    pub authority: Signer<'info>,        pub mint: Account<'info, anchor_spl::token_interface::Mint>,        #[account(        mut,        seeds = [b"metadata", mint.key().as_ref()],        bump,    )]    pub asset_metadata: Account<'info, AssetMetadata>,        #[account(        seeds = [b"auth", mint.key().as_ref()],        bump,        constraint = auth_state.has_role(&authority.key(), Role::Admin) ||                     auth_state.has_role(&authority.key(), Role::Issuer) @ ErrorCode::Unauthorized    )]    pub auth_state: Account<'info, AuthState>,
  1. Line 7 pub authority: Signer<'info>,: Requires this account to have signed the transaction.
  2. Line 13 seeds = [b"metadata", mint.key().as_ref()],: Declares the PDA seeds. Anchor re-derives the address and rejects the account if it doesn't match.
  3. Line 14 bump,: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.

How to run, build and test

These commands come from the repo's own manifests (package.json scripts, Anchor.toml, Cargo, go.mod, Makefile). Check the README for prerequisites and environment variables.

DirectoryCommandRuns
.npm run buildanchor build
.npm run testanchor test
.npm run linteslint . --ext .ts
.npm run deployanchor deploy
sdknpm run buildtsc
sdknpm run testjest
sdknpm run linteslint src --ext .ts
sdk/reactnpm run buildtsc
sdk/clinpm run startnode dist/index.js
sdk/clinpm run buildtsc
.anchor buildcompile programs and generate IDLs
.anchor testlocal validator + test suite
.anchor run testyarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts

What you could build from it