Skip to main content

tengu_api/state/
forge.rs

1use super::DojosAccount;
2use steel::*;
3
4#[repr(C)]
5#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
6pub struct Forge {
7    pub dojo: Pubkey,
8    pub level: u64,
9    pub ore_queued: u64,
10    pub last_refine_slot: u64,
11    pub upgrade_cooldown_slot: u64,
12    pub buffer1: u64,
13    pub buffer2: u64,
14    pub buffer3: u64,
15    pub buffer4: u64,
16}
17
18account!(DojosAccount, Forge);
19
20impl Forge {
21    /// Ore per second throughput.
22    pub fn throughput(level: u64) -> f64 {
23        match level {
24            1 => 1.0 / 8.0,
25            2 => 1.0 / 5.0,
26            3 => 1.0 / 4.0,
27            4 => 1.0 / 3.0,
28            5 => 1.0,
29            6 => 1.0,
30            7 => 1.0,
31            8 => 1.0,       // Lv.8 max: 1.0 ore/s × 0.25 $DOJO/ore = 0.25 $DOJO/s
32            _ => 1.0 / 8.0,
33        }
34    }
35
36    /// Raw $DOJO (6 decimals) per ore. Ore → $DOJO directly (shards).
37    pub fn refine_rate(level: u64) -> u64 {
38        match level {
39            1 => 100_000,   // 0.1 $DOJO/ore
40            2 => 120_000,   // 0.12 $DOJO/ore
41            3 => 150_000,   // 0.15 $DOJO/ore
42            4 => 200_000,   // 0.2 $DOJO/ore
43            5 => 250_000,   // 0.25 $DOJO/ore → 0.25 $DOJO/s
44            6 => 250_000,
45            7 => 250_000,
46            8 => 250_000,   // 0.25 $DOJO/ore → 0.25 $DOJO/s (max)
47            _ => 100_000,
48        }
49    }
50
51    pub fn upgrade_cost(from_level: u64) -> u64 {
52        match from_level {
53            1 => crate::consts::FORGE_COST_1_2,
54            2 => crate::consts::FORGE_COST_2_3,
55            3 => crate::consts::FORGE_COST_3_4,
56            4 => crate::consts::FORGE_COST_4_5,
57            5 => crate::consts::FORGE_COST_5_6,
58            6 => crate::consts::FORGE_COST_6_7,
59            7 => crate::consts::FORGE_COST_7_8,
60            _ => u64::MAX,
61        }
62    }
63
64    /// Forge upgrades always pay SOL.
65    pub fn upgrade_pays_sol(_from_level: u64) -> bool {
66        true
67    }
68
69    pub fn upgrade_cooldown(from_level: u64) -> u64 {
70        match from_level {
71            1 => crate::consts::FORGE_COOLDOWN_1_2,
72            2 => crate::consts::FORGE_COOLDOWN_2_3,
73            3 => crate::consts::FORGE_COOLDOWN_3_4,
74            4 => crate::consts::FORGE_COOLDOWN_4_5,
75            5 => crate::consts::FORGE_COOLDOWN_5_6,
76            6 => crate::consts::FORGE_COOLDOWN_6_7,
77            7 => crate::consts::FORGE_COOLDOWN_7_8,
78            8 => crate::consts::FORGE_COOLDOWN_8,
79            _ => 0,
80        }
81    }
82
83    /// Remaining seconds until cooldown ends. 0 when no cooldown or timer has ended.
84    /// `now` is current Solana slot.
85    pub fn cooldown_remaining_seconds(&self, now: u64) -> u64 {
86        if self.upgrade_cooldown_slot == 0 || now >= self.upgrade_cooldown_slot {
87            return 0;
88        }
89        let remaining_slots = self.upgrade_cooldown_slot - now;
90        (remaining_slots as f64 * crate::consts::SECONDS_PER_SLOT) as u64
91    }
92
93    /// Remaining minutes (floor). For display: 0 when in last minute (e.g. 30 sec left → 0 mins).
94    pub fn cooldown_remaining_minutes(&self, now: u64) -> u64 {
95        self.cooldown_remaining_seconds(now) / 60
96    }
97}