Skip to main content

oil_api/state/
rig.rs

1use serde::{Deserialize, Serialize};
2use steel::*;
3
4use crate::state::rig_pda;
5
6use super::OilAccount;
7
8/// Rig account (one per NFT mint, links NFT to on-chain stats)
9#[repr(C)]
10#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
11pub struct Rig {
12    /// The authority (owner) of this rig (matches NFT owner)
13    pub authority: Pubkey,
14
15    /// NFT mint address (used for PDA derivation)
16    pub mint: Pubkey,
17
18    /// Rig type ID (0-14)
19    pub rig_type: u64,
20
21    /// Unique rig ID (can be NFT edition number)
22    pub rig_id: u64,
23
24    /// Mining power (snapshotted at mint, immutable)
25    pub mining_power: u64,
26
27    /// Fuel requirement for placement (snapshotted at mint, immutable)
28    pub fuel_requirement: u64,
29
30    /// Fuel consumption rate per block (snapshotted at mint, immutable, in atomic units with 11 decimals)
31    pub fuel_consumption_rate: u64,
32
33    /// Purchase price in OIL (minting cost)
34    pub purchase_price: u64,
35
36    /// Timestamp when rig was purchased/minted
37    pub purchased_at: i64,
38
39    /// Plot slot (0 = not placed, 1-5 = slot number)
40    pub plot_slot: u64,
41
42    /// Buffer field (for future extensions)
43    pub buffer_a: u64,
44
45    /// Buffer field (for future extensions)
46    pub buffer_b: u64,
47
48    /// Buffer field (for future extensions)
49    pub buffer_c: u64,
50}
51
52impl Rig {
53    pub fn pda(&self) -> (Pubkey, u8) {
54        rig_pda(self.mint)
55    }
56
57    /// Get rig purchase cost in atomic units (11 decimals)
58    /// Returns None for rig_type 0 (Basic Rig - special starter pack)
59    pub fn get_purchase_cost(rig_type: u64) -> Option<u64> {
60        use crate::consts::ONE_OIL;
61        
62        // Costs in OIL (multiply by 10^11 for atomic units)
63        const RIG_COSTS: [Option<u64>; 15] = [
64            Some(11 * ONE_OIL), // 0: Basic Rig (11 OIL)
65            Some(21 * ONE_OIL), // 1: Small Rig
66            Some(42 * ONE_OIL), // 2: Sensor Rig
67            Some(84 * ONE_OIL), // 3: Compressor Rig
68            Some(168 * ONE_OIL), // 4: Medium Rig
69            Some(336 * ONE_OIL), // 5: Large Rig
70            Some(672 * ONE_OIL), // 6: Advanced Sensor Rig
71            Some(1_344 * ONE_OIL), // 7: Turbo Compressor Rig
72            Some(2_688 * ONE_OIL), // 8: Deep Rig
73            Some(5_376 * ONE_OIL), // 9: Mega Rig
74            Some(10_752 * ONE_OIL), // 10: Epic Sensor Rig
75            Some(21_504 * ONE_OIL), // 11: Ultra Compressor Rig
76            Some(43_008 * ONE_OIL), // 12: Legendary Rig
77            Some(86_016 * ONE_OIL), // 13: Master Rig
78            Some(172_032 * ONE_OIL), // 14: Ultimate Rig
79        ];
80        
81        if rig_type >= 15 {
82            return None;
83        }
84        RIG_COSTS[rig_type as usize]
85    }
86
87    /// Display name for metadata; e.g. "Basic Rig #1", "Small Rig #47"
88    pub fn get_rig_name(rig_type: u64, rig_id: u64) -> String {
89        if rig_type >= 15 {
90            return format!("Unknown Rig #{}", rig_id + 1);
91        }
92        let type_name = Self::rig_type_display_name(rig_type);
93        format!("{} #{}", type_name, rig_id + 1)
94    }
95
96    /// Human-readable name for rig type (for metadata display)
97    pub fn rig_type_display_name(rig_type: u64) -> &'static str {
98        const NAMES: [&str; 15] = [
99            "Basic Rig",
100            "Small Rig",
101            "Sensor Rig",
102            "Compressor Rig",
103            "Medium Rig",
104            "Large Rig",
105            "Advanced Sensor Rig",
106            "Turbo Compressor Rig",
107            "Deep Rig",
108            "Mega Rig",
109            "Epic Sensor Rig",
110            "Ultra Compressor Rig",
111            "Legendary Rig",
112            "Master Rig",
113            "Ultimate Rig",
114        ];
115        if rig_type >= 15 {
116            "Unknown Rig"
117        } else {
118            NAMES[rig_type as usize]
119        }
120    }
121
122    /// Metadata URI by type (rig_1.json .. rig_15.json)
123    pub fn get_rig_metadata_uri(rig_type: u64) -> String {
124        if rig_type >= 15 {
125            return String::new();
126        }
127        format!(
128            "https://raw.githubusercontent.com/oil-protocol/token-metadata/main/metadata/rigs/rig_{}.json",
129            rig_type + 1
130        )
131    }
132
133    /// Model slug for display/traits (rig_1 .. rig_15). Use for UI or off-chain metadata attributes.
134    pub fn model_name(rig_type: u64) -> &'static str {
135        const MODELS: [&str; 15] = [
136            "rig_1", "rig_2", "rig_3", "rig_4", "rig_5", "rig_6", "rig_7", "rig_8",
137            "rig_9", "rig_10", "rig_11", "rig_12", "rig_13", "rig_14", "rig_15",
138        ];
139        if rig_type >= 15 {
140            "rig_unknown"
141        } else {
142            MODELS[rig_type as usize]
143        }
144    }
145
146    pub fn initialize(
147        &mut self,
148        authority: Pubkey,
149        mint: Pubkey,
150        rig_type: u64,
151        rig_id: u64,
152        mining_power: u64,
153        fuel_requirement: u64,
154        fuel_consumption_rate: u64,
155        purchase_price: u64,
156        clock: &Clock,
157    ) {
158        self.authority = authority;
159        self.mint = mint;
160        self.rig_type = rig_type;
161        self.rig_id = rig_id;
162        self.mining_power = mining_power;
163        self.fuel_requirement = fuel_requirement;
164        self.fuel_consumption_rate = fuel_consumption_rate;
165        self.purchase_price = purchase_price;
166        self.purchased_at = clock.unix_timestamp;
167        self.plot_slot = 0; // Not placed initially
168        self.buffer_a = 0;
169        self.buffer_b = 0;
170        self.buffer_c = 0;
171    }
172
173    /// Check if rig is staked (placed on plot)
174    pub fn is_staked(&self) -> bool {
175        self.plot_slot > 0
176    }
177
178    /// Place rig on plot (stake)
179    pub fn place(&mut self, slot: u64) {
180        self.plot_slot = slot;
181    }
182
183    /// Remove rig from plot (unstake)
184    pub fn remove(&mut self) {
185        self.plot_slot = 0;
186    }
187}
188
189account!(OilAccount, Rig);