1use solana_sdk::pubkey::Pubkey;
7use std::str::FromStr;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum Network {
16 Devnet,
17 Mainnet,
18}
19
20impl Default for Network {
21 fn default() -> Self {
22 Network::Mainnet
23 }
24}
25
26pub struct ProgramIds {
32 pub vault: Pubkey,
33 pub cred: Pubkey,
34 pub oxo: Pubkey,
35 pub vtp: Pubkey,
36 pub avp: Pubkey,
37 pub shopping: Pubkey,
38}
39
40impl ProgramIds {
41 pub fn for_network(network: Network) -> Self {
43 match network {
44 Network::Devnet => Self::devnet(),
45 Network::Mainnet => Self::mainnet(),
46 }
47 }
48
49 pub fn devnet() -> Self {
51 Self {
52 vault: Pubkey::from_str("9gKRCrUpHv9CRHwYMmm2zP5bN1bUKgyi7BxuS5jifX4x").unwrap(),
53 cred: Pubkey::from_str("JCzhFrDvipRr5CYtWoV3szpaJ3RP59gbAn4zCi5CZcv8").unwrap(),
54 oxo: Pubkey::from_str("AZZQdfcmejPjebNnneqTeVbkbVY8nyZuomuChbLqwhHj").unwrap(),
55 vtp: Pubkey::from_str("3mP7L31af6MV6FnqWG6E78JELNuizWDwBK3rC3g3WjSK").unwrap(),
56 avp: Pubkey::from_str("FE3ZJBqVcqP6ar2pnndMghgNb3pi4mrjhVoAS7x4BVCA").unwrap(),
57 shopping: Pubkey::from_str("FSqRkH7nkGHP3VpHwFE667PVAfLKfSGaPMgTrXpJZJoJ").unwrap(),
58 }
59 }
60
61 pub fn mainnet() -> Self {
63 Self {
64 vault: Pubkey::from_str("J8HhLeRv5iQaSyYQBXJoDwDKbw4V8uA84WN93YrVSWQT").unwrap(),
65 cred: Pubkey::from_str("HYQJwCJ5wH9o4sb9sVPyvSSeY9DtsznZGy2AfpiBaBaG").unwrap(),
66 oxo: Pubkey::from_str("AZZQdfcmejPjebNnneqTeVbkbVY8nyZuomuChbLqwhHj").unwrap(),
68 vtp: Pubkey::from_str("3mP7L31af6MV6FnqWG6E78JELNuizWDwBK3rC3g3WjSK").unwrap(),
70 avp: Pubkey::from_str("FE3ZJBqVcqP6ar2pnndMghgNb3pi4mrjhVoAS7x4BVCA").unwrap(),
72 shopping: Pubkey::from_str("HiewKEBy6YVn3Xi5xdhyrsfPr3KjKg6Jy8PXemyeteXJ").unwrap(),
73 }
74 }
75}
76
77pub struct TokenMints {
83 pub cred: Pubkey,
84 pub oxo: Pubkey,
85 pub usdc: Pubkey,
86}
87
88impl TokenMints {
89 pub fn for_network(network: Network) -> Self {
91 match network {
92 Network::Devnet => Self::devnet(),
93 Network::Mainnet => Self::mainnet(),
94 }
95 }
96
97 pub fn devnet() -> Self {
99 Self {
100 cred: Pubkey::from_str("DDfGosZop37FA97MqCrXA6fKMu8kTwduQ1JsdYJFoNBP").unwrap(),
101 oxo: Pubkey::from_str("A8UkSCWuFvgBjeqWzZVowyCyUgW3JcyPB8VscPycd9hd").unwrap(),
102 usdc: Pubkey::from_str("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU").unwrap(),
103 }
104 }
105
106 pub fn mainnet() -> Self {
108 Self {
109 cred: Pubkey::from_str("9GQMCAK3MpZF1hEbwqA9d4mRGtippGV9hyr8fxmz6eA").unwrap(),
110 oxo: Pubkey::from_str("A8UkSCWuFvgBjeqWzZVowyCyUgW3JcyPB8VscPycd9hd").unwrap(),
112 usdc: Pubkey::from_str("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v").unwrap(),
113 }
114 }
115}
116
117pub struct MainnetState {
123 pub cred_config: Pubkey,
124 pub shopping_state: Pubkey,
125 pub reserve_vault: Pubkey,
126 pub treasury: Pubkey,
127 pub staker_pool: Pubkey,
128}
129
130impl MainnetState {
131 pub fn get() -> Self {
132 Self {
133 cred_config: Pubkey::from_str("FzwRshrm2Pu8ygMPqHwbjb7yWBiQ2pQc3Lgk8XJRpvNM").unwrap(),
134 shopping_state: Pubkey::from_str("92nXnNG5gJFDEqXE8Lyrqr3nDZiaD2atBCoRSNY5JD3n").unwrap(),
135 reserve_vault: Pubkey::from_str("Ga2PRtFu3TRsTjN1QxdVpvtjVP7kb1rAkZse9MXWXjPh").unwrap(),
136 treasury: Pubkey::from_str("CTRnn7vC1EtL1YDLU3x3iidEcCWRmZupEXHKQfL17Fxa").unwrap(),
137 staker_pool: Pubkey::from_str("zEJf7Vy7ZDjvoMTBndAvkvxRpACUzCboQg2dP8H8R6k").unwrap(),
138 }
139 }
140}
141
142pub const CRED_DECIMALS: u8 = 6;
148pub const OXO_DECIMALS: u8 = 6;
149pub const LAMPORTS_PER_CRED: u64 = 1_000_000;
150pub const LAMPORTS_PER_OXO: u64 = 1_000_000;
151
152pub const USER_SHARE_BPS: u16 = 8000; pub const TREASURY_SHARE_BPS: u16 = 1400; pub const STAKER_SHARE_BPS: u16 = 600; pub const STAKING_APY: [(u16, u16); 5] = [
159 (365, 1500), (180, 1200), (90, 800), (30, 500), (7, 300), ];
165
166pub const STAKE_30D_APY_BPS: u16 = 800; pub const STAKE_90D_APY_BPS: u16 = 1200; pub const STAKE_180D_APY_BPS: u16 = 1600; pub const STAKE_365D_APY_BPS: u16 = 2000; pub const MIN_STAKE_DAYS: u16 = 7;
174pub const MAX_STAKE_DAYS: u16 = 730; pub const EXTRACTION_FEE_BPS: u16 = 500; pub const OXO_TOTAL_SUPPLY: u64 = 1_000_000_000_000_000; pub const MIN_LOCK_SECONDS: i64 = 15_552_000; pub const MAX_LOCK_SECONDS: i64 = 126_144_000; pub const GRADUATION_THRESHOLD: u64 = 25_000_000_000; pub const AGENT_CREATION_FEE: u64 = 500_000_000; pub const TRANSFER_FEE_BPS: u16 = 10; pub const ESCROW_FEE_BPS: u16 = 25; pub const MAX_ARBITERS: u8 = 5;
190pub const MAX_CONDITIONS: u8 = 10;
191
192pub const MIN_SERVICE_AGENT_STAKE: u64 = 500_000_000; pub const MAX_CAPABILITIES: u8 = 20;
195pub const MAX_METADATA_LEN: usize = 200;
196
197pub const SESSION_KEY_TTL_HOURS: u32 = 24;
199pub const SESSION_KEY_MAX_ACTIONS: u32 = 1000;
200
201pub const CONTEXT_RELOAD_TARGET_MS: u32 = 100;
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq)]
210#[repr(u8)]
211pub enum CaptureType {
212 Shopping = 0,
213 Data = 1,
214 Presence = 2,
215 Attention = 3,
216 Referral = 4,
217}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq)]
221#[repr(u8)]
222pub enum PermissionLevel {
223 None = 0,
224 Read = 1,
225 Capture = 2,
226 Guided = 3,
227 Autonomous = 4,
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq)]
232#[repr(u8)]
233pub enum EscrowStatus {
234 Active = 0,
235 Released = 1,
236 Cancelled = 2,
237 Disputed = 3,
238}
239
240#[derive(Debug, Clone, Copy, PartialEq, Eq)]
242#[repr(u8)]
243pub enum AgentType {
244 Personal = 0,
245 Service = 1,
246}
247
248#[derive(Debug, Clone, Copy, PartialEq, Eq)]
250#[repr(u8)]
251pub enum AgentStatus {
252 Active = 0,
253 Suspended = 1,
254 Revoked = 2,
255}
256
257pub const DEVNET_RPC: &str = "https://api.devnet.solana.com";
263pub const MAINNET_RPC: &str = "https://api.mainnet-beta.solana.com";
264
265pub fn rpc_endpoint(network: Network) -> &'static str {
267 match network {
268 Network::Devnet => DEVNET_RPC,
269 Network::Mainnet => MAINNET_RPC,
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn program_ids_are_valid() {
279 let devnet = ProgramIds::devnet();
280 let mainnet = ProgramIds::mainnet();
281
282 assert_ne!(devnet.vault, Pubkey::default());
284 assert_ne!(mainnet.vault, Pubkey::default());
285 }
286
287 #[test]
288 fn distribution_adds_to_100() {
289 assert_eq!(
290 USER_SHARE_BPS + TREASURY_SHARE_BPS + STAKER_SHARE_BPS,
291 10000
292 );
293 }
294
295 #[test]
296 fn staking_apy_increases_with_duration() {
297 for i in 1..STAKING_APY.len() {
298 assert!(STAKING_APY[i-1].1 > STAKING_APY[i].1);
299 }
300 }
301}