oil-api 0.7.8

API for interacting with the OIL protocol on Solana
Documentation
use serde::{Deserialize, Serialize};
use steel::*;

use crate::state::rig_pda;

use super::OilAccount;

/// Rig account (one per NFT mint, links NFT to on-chain stats)
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
pub struct Rig {
    /// The authority (owner) of this rig (matches NFT owner)
    pub authority: Pubkey,

    /// NFT mint address (used for PDA derivation)
    pub mint: Pubkey,

    /// Rig type ID (0-14)
    pub rig_type: u64,

    /// Unique rig ID (can be NFT edition number)
    pub rig_id: u64,

    /// Mining power (snapshotted at mint, immutable)
    pub mining_power: u64,

    /// Fuel requirement for placement (snapshotted at mint, immutable)
    pub fuel_requirement: u64,

    /// Fuel consumption rate per block (snapshotted at mint, immutable, in atomic units with 11 decimals)
    pub fuel_consumption_rate: u64,

    /// Purchase price in OIL (minting cost)
    pub purchase_price: u64,

    /// Timestamp when rig was purchased/minted
    pub purchased_at: i64,

    /// Plot slot (0 = not placed, 1-5 = slot number)
    pub plot_slot: u64,

    /// Buffer field (for future extensions)
    pub buffer_a: u64,

    /// Buffer field (for future extensions)
    pub buffer_b: u64,

    /// Buffer field (for future extensions)
    pub buffer_c: u64,
}

impl Rig {
    pub fn pda(&self) -> (Pubkey, u8) {
        rig_pda(self.mint)
    }

    /// Get rig purchase cost in atomic units (11 decimals)
    /// Returns None for rig_type 0 (Basic Rig - special starter pack)
    pub fn get_purchase_cost(rig_type: u64) -> Option<u64> {
        use crate::consts::ONE_OIL;
        
        // Costs in OIL (multiply by 10^11 for atomic units)
        const RIG_COSTS: [Option<u64>; 15] = [
            Some(11 * ONE_OIL), // 0: Basic Rig (11 OIL)
            Some(21 * ONE_OIL), // 1: Small Rig
            Some(42 * ONE_OIL), // 2: Sensor Rig
            Some(84 * ONE_OIL), // 3: Compressor Rig
            Some(168 * ONE_OIL), // 4: Medium Rig
            Some(336 * ONE_OIL), // 5: Large Rig
            Some(672 * ONE_OIL), // 6: Advanced Sensor Rig
            Some(1_344 * ONE_OIL), // 7: Turbo Compressor Rig
            Some(2_688 * ONE_OIL), // 8: Deep Rig
            Some(5_376 * ONE_OIL), // 9: Mega Rig
            Some(10_752 * ONE_OIL), // 10: Epic Sensor Rig
            Some(21_504 * ONE_OIL), // 11: Ultra Compressor Rig
            Some(43_008 * ONE_OIL), // 12: Legendary Rig
            Some(86_016 * ONE_OIL), // 13: Master Rig
            Some(172_032 * ONE_OIL), // 14: Ultimate Rig
        ];
        
        if rig_type >= 15 {
            return None;
        }
        RIG_COSTS[rig_type as usize]
    }

    /// Display name for metadata; e.g. "Basic Rig #1", "Small Rig #47"
    pub fn get_rig_name(rig_type: u64, rig_id: u64) -> String {
        if rig_type >= 15 {
            return format!("Unknown Rig #{}", rig_id + 1);
        }
        let type_name = Self::rig_type_display_name(rig_type);
        format!("{} #{}", type_name, rig_id + 1)
    }

    /// Human-readable name for rig type (for metadata display)
    pub fn rig_type_display_name(rig_type: u64) -> &'static str {
        const NAMES: [&str; 15] = [
            "Basic Rig",
            "Small Rig",
            "Sensor Rig",
            "Compressor Rig",
            "Medium Rig",
            "Large Rig",
            "Advanced Sensor Rig",
            "Turbo Compressor Rig",
            "Deep Rig",
            "Mega Rig",
            "Epic Sensor Rig",
            "Ultra Compressor Rig",
            "Legendary Rig",
            "Master Rig",
            "Ultimate Rig",
        ];
        if rig_type >= 15 {
            "Unknown Rig"
        } else {
            NAMES[rig_type as usize]
        }
    }

    /// Metadata URI by type (rig_1.json .. rig_15.json)
    pub fn get_rig_metadata_uri(rig_type: u64) -> String {
        if rig_type >= 15 {
            return String::new();
        }
        format!(
            "https://raw.githubusercontent.com/oil-protocol/token-metadata/main/metadata/rigs/rig_{}.json",
            rig_type + 1
        )
    }

    /// Model slug for display/traits (rig_1 .. rig_15). Use for UI or off-chain metadata attributes.
    pub fn model_name(rig_type: u64) -> &'static str {
        const MODELS: [&str; 15] = [
            "rig_1", "rig_2", "rig_3", "rig_4", "rig_5", "rig_6", "rig_7", "rig_8",
            "rig_9", "rig_10", "rig_11", "rig_12", "rig_13", "rig_14", "rig_15",
        ];
        if rig_type >= 15 {
            "rig_unknown"
        } else {
            MODELS[rig_type as usize]
        }
    }

    pub fn initialize(
        &mut self,
        authority: Pubkey,
        mint: Pubkey,
        rig_type: u64,
        rig_id: u64,
        mining_power: u64,
        fuel_requirement: u64,
        fuel_consumption_rate: u64,
        purchase_price: u64,
        clock: &Clock,
    ) {
        self.authority = authority;
        self.mint = mint;
        self.rig_type = rig_type;
        self.rig_id = rig_id;
        self.mining_power = mining_power;
        self.fuel_requirement = fuel_requirement;
        self.fuel_consumption_rate = fuel_consumption_rate;
        self.purchase_price = purchase_price;
        self.purchased_at = clock.unix_timestamp;
        self.plot_slot = 0; // Not placed initially
        self.buffer_a = 0;
        self.buffer_b = 0;
        self.buffer_c = 0;
    }

    /// Check if rig is staked (placed on plot)
    pub fn is_staked(&self) -> bool {
        self.plot_slot > 0
    }

    /// Place rig on plot (stake)
    pub fn place(&mut self, slot: u64) {
        self.plot_slot = slot;
    }

    /// Remove rig from plot (unstake)
    pub fn remove(&mut self) {
        self.plot_slot = 0;
    }
}

account!(OilAccount, Rig);