Skip to content

Commit

Permalink
Add an assets >= liabilities invariant
Browse files Browse the repository at this point in the history
  • Loading branch information
metaproph3t committed Aug 24, 2024
1 parent fd25b70 commit dafaf5a
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 1 deletion.
6 changes: 6 additions & 0 deletions programs/conditional_vault/src/instructions/merge_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ impl<'info, 'c: 'info> InteractWithNewVault<'info> {
assert!(account.amount == *expected_balance);
}

ctx.accounts.vault.invariant(
&ctx.accounts.question,
conditional_token_mints.iter().map(|mint| mint.supply).collect::<Vec<u64>>(),
ctx.accounts.vault_underlying_token_account.amount,
)?;

Ok(())
}
}
6 changes: 6 additions & 0 deletions programs/conditional_vault/src/instructions/redeem_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ impl<'info, 'c: 'info> InteractWithNewVault<'info> {
assert!(mint.supply == *expected_supply);
}

ctx.accounts.vault.invariant(
&ctx.accounts.question,
conditional_token_mints.iter().map(|mint| mint.supply).collect::<Vec<u64>>(),
ctx.accounts.vault_underlying_token_account.amount,
)?;

Ok(())
}
}
6 changes: 6 additions & 0 deletions programs/conditional_vault/src/instructions/split_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ impl<'info, 'c: 'info> InteractWithNewVault<'info> {
assert!(acc.amount == pre_conditional_user_balances[i] + amount);
}

ctx.accounts.vault.invariant(
&ctx.accounts.question,
conditional_token_mints.iter().map(|mint| mint.supply).collect::<Vec<u64>>(),
ctx.accounts.vault_underlying_token_account.amount,
)?;

Ok(())
}
}
41 changes: 40 additions & 1 deletion programs/conditional_vault/src/state/conditional_vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,45 @@ pub struct NewConditionalVault {
pub decimals: u8,
}

impl NewConditionalVault {
/// Checks that the vault's assets are always greater than its potential
/// liabilities. Should be called anytime you mint or burn conditional
/// tokens.
///
/// `conditional_token_supplies` should be in the same order as
/// `vault.conditional_token_mints`.
pub fn invariant(
&self,
question: &Question,
conditional_token_supplies: Vec<u64>,
vault_underlying_balance: u64,
) -> Result<()> {
// if the question isn't resolved, the vault should have more underlying
// tokens than ANY conditional token mint's supply

// if the question is resolved, the vault should have more underlying
// tokens than the sum of the conditional token mint's supplies multiplied
// by their respective payouts

let max_possible_liability = if !question.is_resolved() {
// safe because conditional_token_supplies is non-empty
*conditional_token_supplies.iter().max().unwrap()
} else {
conditional_token_supplies
.iter()
.enumerate()
.map(|(i, supply)| {
*supply * question.payout_numerators[i] as u64 / question.payout_denominator as u64
})
.sum::<u64>()
};

assert!(vault_underlying_balance >= max_possible_liability);

Ok(())
}
}

#[macro_export]
macro_rules! generate_new_vault_seeds {
($vault:expr) => {{
Expand Down Expand Up @@ -56,4 +95,4 @@ macro_rules! generate_vault_seeds {
&[$vault.pda_bump],
]
}};
}
}

0 comments on commit dafaf5a

Please sign in to comment.