1use crate::primitives::{Address, Timestamp};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct TokenConfig {
13 pub name: String,
15 pub symbol: String,
17 pub decimals: u8,
19 pub total_supply: u128,
21 pub initial_distribution: InitialDistribution,
23 pub economics: TokenEconomics,
25}
26
27impl Default for TokenConfig {
28 fn default() -> Self {
29 Self {
30 name: "Tenzro Network Token".to_string(),
31 symbol: "TNZO".to_string(),
32 decimals: 18,
33 total_supply: 1_000_000_000u128 * 10u128.pow(18), initial_distribution: InitialDistribution::default(),
35 economics: TokenEconomics::default(),
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
42pub struct InitialDistribution {
43 pub treasury: u128,
45 pub team: u128,
47 pub investors: u128,
49 pub community: u128,
51 pub provider_incentives: u128,
53 pub liquidity: u128,
55}
56
57impl Default for InitialDistribution {
58 fn default() -> Self {
59 let total = 1_000_000_000u128 * 10u128.pow(18); Self {
61 treasury: (total * 25) / 100, team: (total * 10) / 100, investors: (total * 10) / 100, community: (total * 35) / 100, provider_incentives: (total * 15) / 100, liquidity: (total * 5) / 100, }
68 }
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73pub struct TokenEconomics {
74 pub inflation_rate: u32,
76 pub transaction_fee_bps: u32,
78 pub staking_reward_rate: u32,
80 pub burn_rate_bps: u32,
82 pub min_stake: u128,
84}
85
86impl Default for TokenEconomics {
87 fn default() -> Self {
88 Self {
89 inflation_rate: 200, transaction_fee_bps: 10, staking_reward_rate: 500, burn_rate_bps: 5000, min_stake: 1000u128 * 10u128.pow(18), }
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
100pub struct Treasury {
101 pub address: Address,
103 pub balance: u128,
105 pub allocated_grants: u128,
107 pub spent_development: u128,
109 pub spent_marketing: u128,
111 pub reserved: u128,
113 pub parameters: TreasuryParameters,
115}
116
117impl Treasury {
118 pub fn new(address: Address, initial_balance: u128) -> Self {
120 Self {
121 address,
122 balance: initial_balance,
123 allocated_grants: 0,
124 spent_development: 0,
125 spent_marketing: 0,
126 reserved: 0,
127 parameters: TreasuryParameters::default(),
128 }
129 }
130
131 pub fn available_balance(&self) -> Option<u128> {
133 self.balance
134 .checked_sub(self.allocated_grants)?
135 .checked_sub(self.reserved)
136 }
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
141pub struct TreasuryParameters {
142 pub max_grant_amount: u128,
144 pub min_proposal_threshold: u128,
146 pub grant_approval_quorum: u32,
148}
149
150impl Default for TreasuryParameters {
151 fn default() -> Self {
152 Self {
153 max_grant_amount: 1_000_000u128 * 10u128.pow(18), min_proposal_threshold: 10_000u128 * 10u128.pow(18), grant_approval_quorum: 5000, }
157 }
158}
159
160#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
162pub struct StakingPool {
163 pub pool_id: String,
165 pub operator: Address,
167 pub pool_type: PoolType,
169 pub total_staked: u128,
171 pub staker_count: u64,
173 pub commission_rate: u32,
175 pub status: PoolStatus,
177 pub metadata: HashMap<String, String>,
179}
180
181impl StakingPool {
182 pub fn new(operator: Address, pool_type: PoolType) -> Self {
184 Self {
185 pool_id: uuid::Uuid::new_v4().to_string(),
186 operator,
187 pool_type,
188 total_staked: 0,
189 staker_count: 0,
190 commission_rate: 1000, status: PoolStatus::Active,
192 metadata: HashMap::new(),
193 }
194 }
195
196 pub fn add_stake(&mut self, amount: u128) -> Result<(), &'static str> {
198 self.total_staked = self.total_staked
199 .checked_add(amount)
200 .ok_or("Stake addition would overflow")?;
201 self.staker_count = self.staker_count
202 .checked_add(1)
203 .ok_or("Staker count would overflow")?;
204 Ok(())
205 }
206
207 pub fn remove_stake(&mut self, amount: u128) -> Result<(), &'static str> {
209 self.total_staked = self.total_staked
210 .checked_sub(amount)
211 .ok_or("Insufficient stake to remove")?;
212 self.staker_count = self.staker_count
213 .checked_sub(1)
214 .ok_or("Staker count underflow")?;
215 Ok(())
216 }
217}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
221pub enum PoolType {
222 Validator,
224 TeeProvider,
226 ModelProvider,
228 StorageProvider,
230 Trainer,
232 Syncer,
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
238pub enum PoolStatus {
239 Active,
241 Full,
243 Paused,
245 Closed,
247}
248
249#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
251pub struct ProviderStake {
252 pub provider: Address,
254 pub provider_type: ProviderType,
256 pub staked_amount: u128,
258 pub staked_at: Timestamp,
260 pub lock_until: Option<Timestamp>,
262 pub rewards_earned: u128,
264 pub status: StakeStatus,
266}
267
268impl ProviderStake {
269 pub fn new(provider: Address, provider_type: ProviderType, amount: u128) -> Self {
271 Self {
272 provider,
273 provider_type,
274 staked_amount: amount,
275 staked_at: Timestamp::now(),
276 lock_until: None,
277 rewards_earned: 0,
278 status: StakeStatus::Active,
279 }
280 }
281
282 pub fn with_lock_period(mut self, duration_ms: i64) -> Self {
284 self.lock_until = Some(Timestamp::new(
285 Timestamp::now().as_millis() + duration_ms,
286 ));
287 self
288 }
289
290 pub fn is_locked(&self) -> bool {
292 if let Some(lock_until) = self.lock_until {
293 Timestamp::now() < lock_until
294 } else {
295 false
296 }
297 }
298
299 pub fn add_rewards(&mut self, amount: u128) -> Result<(), &'static str> {
301 self.rewards_earned = self.rewards_earned
302 .checked_add(amount)
303 .ok_or("Reward addition would overflow")?;
304 Ok(())
305 }
306}
307
308#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
310pub enum ProviderType {
311 Validator,
313 TeeProvider,
315 ModelProvider,
317 StorageProvider,
319 Trainer,
321 Syncer,
323}
324
325#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
327pub enum StakeStatus {
328 Active,
330 Unbonding,
332 Slashed,
334 Withdrawn,
336}
337
338#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
340pub struct GovernanceProposal {
341 pub proposal_id: String,
343 pub title: String,
345 pub description: String,
347 pub proposer: Address,
349 pub proposal_type: ProposalType,
351 pub voting_start: Timestamp,
353 pub voting_end: Timestamp,
355 pub status: ProposalStatus,
357 pub votes_for: u128,
359 pub votes_against: u128,
361 pub total_voting_power: u128,
363 pub execution_data: Option<Vec<u8>>,
365}
366
367impl GovernanceProposal {
368 pub fn new(
370 title: String,
371 description: String,
372 proposer: Address,
373 proposal_type: ProposalType,
374 voting_duration_ms: i64,
375 ) -> Self {
376 let now = Timestamp::now();
377 Self {
378 proposal_id: uuid::Uuid::new_v4().to_string(),
379 title,
380 description,
381 proposer,
382 proposal_type,
383 voting_start: now,
384 voting_end: Timestamp::new(now.as_millis() + voting_duration_ms),
385 status: ProposalStatus::Active,
386 votes_for: 0,
387 votes_against: 0,
388 total_voting_power: 0,
389 execution_data: None,
390 }
391 }
392
393 pub fn is_voting_open(&self) -> bool {
395 let now = Timestamp::now();
396 now >= self.voting_start && now < self.voting_end && self.status == ProposalStatus::Active
397 }
398
399 pub fn approval_percentage(&self) -> u32 {
401 if self.total_voting_power == 0 {
402 0
403 } else {
404 ((self.votes_for as f64 / self.total_voting_power as f64) * 10000.0) as u32
405 }
406 }
407}
408
409#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
411pub enum ProposalType {
412 ParameterChange { parameter: String, new_value: String },
414 TreasuryGrant { recipient: Address, amount: u128 },
416 ProtocolUpgrade { version: String, code_hash: Vec<u8> },
418 AdaptiveBurnConfigUpdate {
423 base_fee_burn_bps: u16,
424 local_fee_burn_bps: u16,
425 paymaster_burn_bps: u16,
426 },
427 SupplyTargetsUpdate {
432 epoch_neutral_band_bps: u16,
433 rolling_window_epochs: u32,
434 inflation_alarm_bps: u16,
435 deflation_alarm_bps: u16,
436 target_annual_supply_bps: i32,
437 gain_bps_per_pct: u16,
438 magnitude_cap_normal_bps: u16,
439 magnitude_cap_alarm_bps: u16,
440 auto_proposal_min_magnitude_bps: u16,
441 alarm_fast_track_enabled: bool,
442 alarm_timelock_hours: u32,
443 },
444 SeedAgentEarmarkUpdate {
450 enabled: bool,
453 allocation_topup_wei: u128,
457 is_initial_seed: bool,
461 surplus_burn_bps: u16,
464 },
465 SeedAgentCharterUpsert {
471 charter_blob: Vec<u8>,
474 },
475 SeedAgentStatusSet {
479 agent_did: String,
480 status: String,
483 },
484 Custom { proposal_data: Vec<u8> },
486}
487
488#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
490pub enum ProposalStatus {
491 Active,
493 Passed,
495 Failed,
497 Cancelled,
499 Executed,
501}