diff --git a/lib/shared.ak b/lib/shared.ak index 0569500..95f8225 100644 --- a/lib/shared.ak +++ b/lib/shared.ak @@ -132,6 +132,19 @@ pub fn count_orders(tx_inputs: List) -> Int { } } +// Taken from unmerged PR: https://github.com/aiken-lang/stdlib/pull/73/files +pub fn is_sqrt(self: Int, x: Int) -> Bool { + x * x <= self && ( x + 1 ) * ( x + 1 ) > self +} + +test is_sqrt1() { + is_sqrt(44203, 210) +} + +test is_sqrt2() { + is_sqrt(975461057789971041, 987654321) +} + /// Check whether a specific value has *exactly* the right amount of tokens /// This is important to, for example, efficiently check the pool output has the correct value /// Check where this is used, because it's a very subtle bit of logic for where this is safe to do diff --git a/validators/pool.ak b/validators/pool.ak index 21d7f81..39489c1 100644 --- a/validators/pool.ak +++ b/validators/pool.ak @@ -3,7 +3,6 @@ use aiken/dict use aiken/hash use aiken/interval use aiken/list -use aiken/math use aiken/transaction.{ InlineDatum, Input, Mint, Output, OutputReference, ScriptContext, Transaction, TransactionId, @@ -387,11 +386,14 @@ validator(settings_policy_id: PolicyId) { coin_a_amt } - // Calculate the initial number of LP tokens; In particular, we adopt Uniswaps convention of - // computing this value as the square root of the product of the two values. + // Check that the quantity of LP tokens is correct; In particular, we adopt Uniswaps convention of + // using the sqrt of the product of the two values for the initial number of LP tokens to mint.. // This helps minimize precision loss: it gives decent initial liquidity values for a range of // sizes of pools, such that an individual LP token is granular enough for depositing and withdrawing for most users. - expect Some(initial_lq) = math.sqrt(coin_a_amt_sans_protocol_fees * coin_b_amt) + // In particular, though, we don't calculate the sqrt here, which is an expensive function; we instead verify that the + // amount minted is valid by checking that it squares to the correct product + let initial_lq = pool_output_datum.circulating_lp + expect shared.is_sqrt(coin_a_amt_sans_protocol_fees * coin_b_amt, initial_lq) // And check that we mint the correct tokens, and nothing else. let expected_mint =