Skip to content

Commit

Permalink
perp-4041 | 0-offset OutcomeId, less panciky code
Browse files Browse the repository at this point in the history
  • Loading branch information
lvn-rusty-dragon committed Sep 3, 2024
1 parent ae18827 commit dbecbf6
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 113 deletions.
21 changes: 6 additions & 15 deletions contract/src/cpmm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,21 @@ impl StoredMarket {
let mut product_others = Decimal256::one();
let mut invariant = Decimal256::one();

for (idx, outcome) in self.outcomes.iter_mut().enumerate() {
let id = OutcomeId(u8::try_from(idx + 1)?);

for outcome in self.outcomes.iter_mut() {
// Calculate the invariant _before_ scaling up the token counts.
invariant *= outcome.pool_tokens.0;

let old_tokens = outcome.pool_tokens;
outcome.pool_tokens *= new_funds / self.pool_size;
outcome.total_tokens += outcome.pool_tokens - old_tokens;
if id != selected_outcome {
if outcome.id != selected_outcome {
product_others *= outcome.pool_tokens.0;
}
}

let pool_selected = Token(invariant / product_others);

let outcome = self
.outcomes
.get_mut(usize::from(selected_outcome.0 - 1))
.unwrap();
let outcome = self.get_outcome_mut(selected_outcome)?;
let returned = outcome.pool_tokens - pool_selected;
outcome.pool_tokens = pool_selected;
self.pool_size = new_funds;
Expand All @@ -52,14 +47,11 @@ impl StoredMarket {
///
/// Returns the amount of liquidity freed up.
pub fn sell(&mut self, selected_outcome: OutcomeId, tokens: Token) -> Result<Collateral> {
self.assert_valid_outcome(selected_outcome)?;

let mut invariant = Decimal256::one();
let mut product = Decimal256::one();
for (idx, outcome) in self.outcomes.iter_mut().enumerate() {
for outcome in self.outcomes.iter_mut() {
invariant *= outcome.pool_tokens.0;
let id = OutcomeId(u8::try_from(idx + 1)?);
if id == selected_outcome {
if outcome.id == selected_outcome {
outcome.pool_tokens += tokens;
}
product *= outcome.pool_tokens.0;
Expand All @@ -83,8 +75,7 @@ impl StoredMarket {

/// Winnings for the given number of tokens in the given winner.
pub(crate) fn winnings_for(&self, winner: OutcomeId, tokens: Token) -> Result<Collateral> {
self.assert_valid_outcome(winner)?;
let outcome = self.outcomes.get(usize::from(winner.0 - 1)).unwrap();
let outcome = self.get_outcome(winner)?;
(self.pool_size * (tokens / outcome.total_tokens)).map_err(Error::from)
}
}
8 changes: 7 additions & 1 deletion contract/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ pub enum Error {
)]
InvalidOutcome {
id: MarketId,
outcome_count: u32,
/// Use a String to avoid trying to serialize a usize or convert to a u32
outcome_count: String,
outcome: OutcomeId,
},
#[error("Winner already set for market {id}")]
Expand All @@ -96,4 +97,9 @@ pub enum Error {
NoAppointedAdmin {},
#[error("You are not the appointed admin")]
NotAppointedAdmin {},
#[error("Too many outcomes specified, we found index {idx}. {source}")]
TooManyOutcomes {
idx: String,
source: std::num::TryFromIntError,
},
}
64 changes: 29 additions & 35 deletions contract/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> R
}
}

pub(crate) fn to_stored_outcome(outcomes: Vec<OutcomeDef>) -> (Vec<StoredOutcome>, Collateral) {
pub(crate) fn to_stored_outcome(
outcomes: Vec<OutcomeDef>,
) -> Result<(Vec<StoredOutcome>, Collateral)> {
let mut total = Collateral::zero();
let outcomes = outcomes
.into_iter()
Expand All @@ -57,18 +59,18 @@ pub(crate) fn to_stored_outcome(outcomes: Vec<OutcomeDef>) -> (Vec<StoredOutcome
},
)| {
total += initial_amount;
let id = OutcomeId(u8::try_from(idx + 1).unwrap());
let id = OutcomeId::try_from(idx)?;
let pool_tokens = Token(Decimal256::from_ratio(initial_amount.0, 1u8));
StoredOutcome {
Ok(StoredOutcome {
id,
label,
pool_tokens,
total_tokens: pool_tokens,
}
})
},
)
.collect();
(outcomes, total)
.collect::<Result<_>>()?;
Ok((outcomes, total))
}

fn add_market(
Expand Down Expand Up @@ -107,7 +109,7 @@ fn add_market(
.map_or_else(MarketId::one, MarketId::next);
LAST_MARKET_ID.save(deps.storage, &id)?;
let arbitrator = deps.api.addr_validate(&arbitrator)?;
let (outcomes, total) = to_stored_outcome(outcomes);
let (outcomes, total) = to_stored_outcome(outcomes)?;
if total != funds {
return Err(Error::IncorrectFundsPerOutcome {
provided: funds,
Expand Down Expand Up @@ -168,17 +170,14 @@ fn deposit(

assert_eq!(share_info.outcomes.len(), market.outcomes.len());

let outcome_tokens = share_info
.outcomes
.get_mut(usize::from(outcome.0) - 1)
.unwrap();
let outcome_tokens = share_info.get_outcome_mut(id, outcome).unwrap();
*outcome_tokens += tokens;
share_info.save(deps.storage, &market, &info.sender)?;
Ok(Response::new().add_event(
Event::new("deposit")
.add_attribute("market-id", id.0.to_string())
.add_attribute("outcome-id", outcome.0.to_string())
.add_attribute("tokens", tokens.0.to_string())
.add_attribute("market-id", id.to_string())
.add_attribute("outcome-id", outcome.to_string())
.add_attribute("tokens", tokens.to_string())
.add_attribute("deposit-amount", deposit_amount.to_string())
.add_attribute("fee", fee.to_string()),
))
Expand All @@ -205,10 +204,10 @@ fn withdraw(
let mut share_info = ShareInfo::load(deps.storage, &market, &info.sender)?
.ok_or(Error::NoPositionsOnMarket { id })?;

let user_tokens = share_info
.outcomes
.get_mut(usize::from(outcome.0 - 1))
.ok_or(Error::NoTokensFound { id, outcome })?;
let user_tokens = share_info.get_outcome_mut(id, outcome)?;
if user_tokens.is_zero() {
return Err(Error::NoTokensFound { id, outcome });
}

if *user_tokens < tokens {
return Err(Error::InsufficientTokens {
Expand All @@ -233,9 +232,9 @@ fn withdraw(
Ok(Response::new()
.add_event(
Event::new("deposit")
.add_attribute("market-id", id.0.to_string())
.add_attribute("outcome-id", outcome.0.to_string())
.add_attribute("tokens", tokens.0.to_string())
.add_attribute("market-id", id.to_string())
.add_attribute("outcome-id", outcome.to_string())
.add_attribute("tokens", tokens.to_string())
.add_attribute("fee", fee.to_string())
.add_attribute("withdrawal", funds.to_string()),
)
Expand Down Expand Up @@ -273,14 +272,10 @@ fn set_winner(
return Err(Error::WinnerAlreadySet { id });
}

market.assert_valid_outcome(outcome)?;
market.winner = Some(outcome);
MARKETS.save(deps.storage, id, &market)?;

let house_winnings = market.winnings_for(
outcome,
market.outcomes[usize::from(outcome.0 - 1)].pool_tokens,
)?;
let house_winnings = market.winnings_for(outcome, market.get_outcome(outcome)?.pool_tokens)?;

Ok(Response::new()
.add_event(
Expand All @@ -306,16 +301,15 @@ fn collect(deps: DepsMut, info: MessageInfo, id: MarketId) -> Result<Response> {
return Err(Error::AlreadyClaimedWinnings { id });
}
share_info.claimed_winnings = true;
let tokens =
share_info
.outcomes
.get(usize::from(winner.0 - 1))
.ok_or(Error::NoTokensFound {
id,
outcome: winner,
})?;
let tokens = share_info.get_outcome(id, winner)?;
if tokens.is_zero() {
return Err(Error::NoTokensFound {
id,
outcome: winner,
});
}
share_info.save(deps.storage, &market, &info.sender)?;
let winnings = market.winnings_for(winner, *tokens)?;
let winnings = market.winnings_for(winner, tokens)?;

Ok(Response::new()
.add_event(
Expand Down
52 changes: 43 additions & 9 deletions contract/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,32 @@ impl ShareInfo {
assert_eq!(market.outcomes.len(), self.outcomes.len());
SHARES.save(store, (market.id, addr), self)
}

pub(crate) fn get_outcome(&self, id: MarketId, outcome: OutcomeId) -> Result<Token> {
self.outcomes
.get(outcome.usize())
.copied()
.ok_or_else(|| Error::InvalidOutcome {
id,
outcome_count: self.outcomes.len().to_string(),
outcome,
})
}

pub(crate) fn get_outcome_mut(
&mut self,
id: MarketId,
outcome: OutcomeId,
) -> Result<&mut Token> {
let count = self.outcomes.len();
self.outcomes
.get_mut(outcome.usize())
.ok_or_else(|| Error::InvalidOutcome {
id,
outcome_count: count.to_string(),
outcome,
})
}
}

#[derive(Serialize, Deserialize)]
Expand All @@ -63,17 +89,25 @@ impl StoredMarket {
.ok_or(Error::MarketNotFound { id })
}

pub(crate) fn assert_valid_outcome(&self, outcome_id: OutcomeId) -> Result<()> {
let outcome = usize::from(outcome_id.0);
if outcome == 0 || outcome > self.outcomes.len() {
Err(Error::InvalidOutcome {
pub(crate) fn get_outcome(&self, outcome: OutcomeId) -> Result<&StoredOutcome> {
self.outcomes
.get(outcome.usize())
.ok_or_else(|| Error::InvalidOutcome {
id: self.id,
outcome_count: u32::try_from(self.outcomes.len())?,
outcome: outcome_id,
outcome_count: self.outcomes.len().to_string(),
outcome,
})
}

pub(crate) fn get_outcome_mut(&mut self, outcome: OutcomeId) -> Result<&mut StoredOutcome> {
let count = self.outcomes.len();
self.outcomes
.get_mut(outcome.usize())
.ok_or_else(|| Error::InvalidOutcome {
id: self.id,
outcome_count: count.to_string(),
outcome,
})
} else {
Ok(())
}
}
}

Expand Down
Loading

0 comments on commit dbecbf6

Please sign in to comment.