Skip to content

Commit 584b061

Browse files
feat: implement market creation
1 parent ec65699 commit 584b061

3 files changed

Lines changed: 172 additions & 1 deletion

File tree

contracts/src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ use soroban_sdk::contracterror;
55
#[repr(u32)]
66
pub enum PredictXError {
77
NotImplemented = 1,
8+
EmptyTitle = 2,
9+
EmptyDescription = 3,
10+
InvalidOutcomeCount = 4,
11+
InvalidEndTime = 5,
812
}

contracts/src/lib.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ pub mod resolution;
88
pub mod rewards;
99
pub mod storage;
1010

11-
use soroban_sdk::{contract, contractimpl, Env, String};
11+
use crate::{
12+
errors::PredictXError,
13+
market::Market,
14+
storage::{get_next_market_id, save_market},
15+
};
16+
use soroban_sdk::{contract, contractimpl, Env, String, Vec};
1217

1318
#[contract]
1419
pub struct PredictXContract;
@@ -18,6 +23,45 @@ impl PredictXContract {
1823
pub fn version(env: Env) -> String {
1924
String::from_str(&env, env!("CARGO_PKG_VERSION"))
2025
}
26+
27+
pub fn create_market(
28+
env: Env,
29+
title: String,
30+
description: String,
31+
end_time: u64,
32+
outcomes: Vec<String>,
33+
) -> Result<u64, PredictXError> {
34+
if title.len() == 0 {
35+
return Err(PredictXError::EmptyTitle);
36+
}
37+
38+
if description.len() == 0 {
39+
return Err(PredictXError::EmptyDescription);
40+
}
41+
42+
if outcomes.len() < 2 {
43+
return Err(PredictXError::InvalidOutcomeCount);
44+
}
45+
46+
if end_time <= env.ledger().timestamp() {
47+
return Err(PredictXError::InvalidEndTime);
48+
}
49+
50+
let market_id = get_next_market_id(&env);
51+
let market = Market {
52+
id: market_id,
53+
creator: env.current_contract_address(),
54+
title,
55+
description,
56+
end_time,
57+
outcomes,
58+
resolved: false,
59+
};
60+
61+
save_market(&env, &market);
62+
63+
Ok(market_id)
64+
}
2165
}
2266

2367
#[cfg(test)]

contracts/src/tests.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::{PredictXContract, PredictXContractClient};
22
use crate::{
3+
errors::PredictXError,
34
market::Market,
45
storage::{get_market, get_next_market_id, save_market},
56
};
@@ -63,3 +64,125 @@ fn returns_none_for_missing_market() {
6364
assert_eq!(get_market(&env, 404), None);
6465
});
6566
}
67+
68+
#[test]
69+
fn creates_market_successfully() {
70+
let env = Env::default();
71+
let contract_id = env.register(PredictXContract, ());
72+
73+
env.as_contract(&contract_id, || {
74+
let outcomes = vec![
75+
&env,
76+
String::from_str(&env, "Yes"),
77+
String::from_str(&env, "No"),
78+
];
79+
let market_id = PredictXContract::create_market(
80+
env.clone(),
81+
String::from_str(&env, "Will PredictX launch on testnet?"),
82+
String::from_str(&env, "A scaffolded market creation test."),
83+
env.ledger().timestamp() + 1,
84+
outcomes.clone(),
85+
)
86+
.unwrap();
87+
88+
let market = get_market(&env, market_id).unwrap();
89+
90+
assert_eq!(market.id, market_id);
91+
assert_eq!(market.creator, env.current_contract_address());
92+
assert_eq!(
93+
market.title,
94+
String::from_str(&env, "Will PredictX launch on testnet?")
95+
);
96+
assert_eq!(
97+
market.description,
98+
String::from_str(&env, "A scaffolded market creation test.")
99+
);
100+
assert_eq!(market.end_time, env.ledger().timestamp() + 1);
101+
assert_eq!(market.outcomes, outcomes);
102+
assert!(!market.resolved);
103+
});
104+
}
105+
106+
#[test]
107+
fn rejects_empty_title() {
108+
let env = Env::default();
109+
let contract_id = env.register(PredictXContract, ());
110+
111+
env.as_contract(&contract_id, || {
112+
let result = PredictXContract::create_market(
113+
env.clone(),
114+
String::from_str(&env, ""),
115+
String::from_str(&env, "A valid description."),
116+
env.ledger().timestamp() + 1,
117+
vec![
118+
&env,
119+
String::from_str(&env, "Yes"),
120+
String::from_str(&env, "No"),
121+
],
122+
);
123+
124+
assert_eq!(result, Err(PredictXError::EmptyTitle));
125+
});
126+
}
127+
128+
#[test]
129+
fn rejects_empty_description() {
130+
let env = Env::default();
131+
let contract_id = env.register(PredictXContract, ());
132+
133+
env.as_contract(&contract_id, || {
134+
let result = PredictXContract::create_market(
135+
env.clone(),
136+
String::from_str(&env, "A valid title"),
137+
String::from_str(&env, ""),
138+
env.ledger().timestamp() + 1,
139+
vec![
140+
&env,
141+
String::from_str(&env, "Yes"),
142+
String::from_str(&env, "No"),
143+
],
144+
);
145+
146+
assert_eq!(result, Err(PredictXError::EmptyDescription));
147+
});
148+
}
149+
150+
#[test]
151+
fn rejects_invalid_outcome_count() {
152+
let env = Env::default();
153+
let contract_id = env.register(PredictXContract, ());
154+
155+
env.as_contract(&contract_id, || {
156+
let result = PredictXContract::create_market(
157+
env.clone(),
158+
String::from_str(&env, "A valid title"),
159+
String::from_str(&env, "A valid description."),
160+
env.ledger().timestamp() + 1,
161+
vec![&env, String::from_str(&env, "Only one outcome")],
162+
);
163+
164+
assert_eq!(result, Err(PredictXError::InvalidOutcomeCount));
165+
});
166+
}
167+
168+
#[test]
169+
fn rejects_invalid_end_time() {
170+
let env = Env::default();
171+
let contract_id = env.register(PredictXContract, ());
172+
173+
env.as_contract(&contract_id, || {
174+
let result = PredictXContract::create_market(
175+
env.clone(),
176+
String::from_str(&env, "A valid title"),
177+
String::from_str(&env, "A valid description."),
178+
env.ledger().timestamp(),
179+
vec![
180+
&env,
181+
String::from_str(&env, "Yes"),
182+
String::from_str(&env, "No"),
183+
],
184+
);
185+
186+
assert_eq!(result, Err(PredictXError::InvalidEndTime));
187+
});
188+
}

0 commit comments

Comments
 (0)