Untitled

 avatar
unknown
plain_text
5 months ago
6.5 kB
2
Indexable
use anchor_lang::prelude::*;
use anchor_lang::solana_program::hash::hash;

declare_id!("BiZguh7AWYWwvL8EykRT6YWCX1pge4NtVRkt3C9yUtKW");

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

    pub fn initialize(ctx: Context<Initialize>, max_documents: u32) -> Result<()> {
        let global_state = &mut ctx.accounts.global_state;
        global_state.document_count = 0;
        global_state.max_documents = max_documents;
        global_state.document_addresses = vec![Pubkey::default(); max_documents as usize];
        Ok(())
    }

    pub fn store_document(
        ctx: Context<StoreDocument>,
        bill_of_lading_number: String,
        ship_from: String,
        ship_to: String,
        ship_date: i64,
        carrier: String,
        cargo: String,
        value_usd: u64,
        doc_metadata: String,
        owner: Pubkey,
    ) -> Result<()> {
        let document = &mut ctx.accounts.document;
        let global_state = &mut ctx.accounts.global_state;

        require!(
            (global_state.document_count as usize) < global_state.document_addresses.len(),
            DocError::MaxDocumentsReached
        );

        let clock: Clock = Clock::get().unwrap();

        // Generate document hash
        let hash_input = format!(
            "{}{}{}{}{}{}{}",
            bill_of_lading_number, ship_from, ship_to, ship_date, carrier, cargo, value_usd
        );
        let document_hash = hash(hash_input.as_bytes());

        // Store document information
        document.document_hash = document_hash.to_bytes();
        document.timestamp = clock.unix_timestamp;
        document.issuer = ctx.accounts.issuer.key();
        document.doc_metadata = doc_metadata;
        document.bill_of_lading_number = bill_of_lading_number;
        document.owner = owner;

        // Store document address in global state
        let _index = global_state.document_count as usize;
        global_state.document_addresses[_index] = document.key();
        global_state.document_count += 1;
        msg!(
            "document created BL num = {} at timestamp = {} with hash = {:?}, owner = {} ",
            document.bill_of_lading_number,
            document.timestamp,
            document.document_hash,
            document.owner
        );
        Ok(())
    }

    pub fn verify_document(ctx: Context<VerifyDocument>, input_hash: [u8; 32]) -> Result<bool> {
        let document = &ctx.accounts.document;
        let stored_hash = document.document_hash;
        let is_valid = input_hash == stored_hash;
        msg!("verifyDocument = {} ", is_valid);
        Ok(is_valid)
    }

    pub fn get_document_count(ctx: Context<GetDocumentCount>) -> Result<u64> {
        msg!(
            "get_document_count = {} ",
            ctx.accounts.global_state.document_count
        );

        Ok(ctx.accounts.global_state.document_count)
    }

    pub fn get_document_addresses(
        ctx: Context<GetDocumentAddresses>,
        start_index: u32,
        limit: u32,
    ) -> Result<Vec<Pubkey>> {
        let global_state = &ctx.accounts.global_state;
        let end_index = (start_index + limit).min(global_state.document_count as u32);
        Ok(global_state.document_addresses[start_index as usize..end_index as usize].to_vec())
    }

    pub fn get_document_owner(
        ctx: Context<GetDocumentOwner>,
        bill_of_lading_number: String,
    ) -> Result<Pubkey> {
        msg!("get_document_owner = {}", ctx.accounts.document.owner);
        let doc = &mut ctx.accounts.document;

        Ok(doc.owner)
    }

    pub fn change_document_owner(
        ctx: Context<ChangeDocumentOwner>,
        bill_of_lading_number: String,
        new_owner: Pubkey,
    ) -> Result<()> {
        let doc = &mut ctx.accounts.document;

        msg!(
            "get_document_owner = old {} vs new {} ",
            doc.owner,
            new_owner
        );

        doc.owner = new_owner.key();
        msg!("Owner change successful.");
        Ok(())
    }
}

#[derive(Accounts)]
#[instruction(max_documents: u32)]
pub struct Initialize<'info> {
    #[account(
        init,
        payer = authority,
        space = 8 + 8 + 4 + 4 + (32 * max_documents as usize), // Discriminator + document_count + max_documents + vec length + document addresses
        seeds = [b"global_state"],
        bump
    )]
    pub global_state: Account<'info, GlobalState>,
    #[account(mut)]
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
#[instruction(bill_of_lading_number: String)]
pub struct StoreDocument<'info> {
    #[account(
        init,
        payer = issuer,
        space = 8 + 32 + 8 + 32 + 300 + 500, // Increased space for strings
        seeds = [b"document", bill_of_lading_number.as_bytes()],
        bump
    )]
    pub document: Account<'info, Document>,
    #[account(mut)]
    pub global_state: Account<'info, GlobalState>,
    #[account(mut)]
    pub issuer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct VerifyDocument<'info> {
    pub document: Account<'info, Document>,
}

#[derive(Accounts)]
pub struct GetDocumentCount<'info> {
    pub global_state: Account<'info, GlobalState>,
}

#[derive(Accounts)]
pub struct GetDocumentAddresses<'info> {
    pub global_state: Account<'info, GlobalState>,
}

#[derive(Accounts)]
#[instruction(bill_of_lading_number: String)]
pub struct GetDocumentOwner<'info> {
    #[account(
        seeds = [b"document", bill_of_lading_number.as_bytes()],
        bump
    )]
    pub document: Account<'info, Document>,
}

#[derive(Accounts)]
#[instruction(bill_of_lading_number: String)]
pub struct ChangeDocumentOwner<'info> {
    #[account(
        seeds = [b"document", bill_of_lading_number.as_bytes()],
        bump,
    )]
    pub document: Account<'info, Document>,
}
#[account]
pub struct GlobalState {
    pub document_count: u64,
    pub max_documents: u32,
    pub document_addresses: Vec<Pubkey>,
}

#[account]
pub struct Document {
    pub document_hash: [u8; 32],
    pub timestamp: i64,
    pub issuer: Pubkey,
    pub doc_metadata: String,
    pub bill_of_lading_number: String,
    pub owner: Pubkey,
}

#[error_code]
pub enum DocError {
    #[msg("Not valid authentication")]
    NotValidAuth,
    #[msg("Bill of Lading does not exist")]
    BlNotExisting,
    #[msg("Maximum number of documents reached")]
    MaxDocumentsReached,
    #[msg("Not authorized to perform this action")]
    NotAuthorized,
    #[msg("Default error")]
    DefaultErr,
}
Editor is loading...
Leave a Comment