Skip to content

Commit b6bc2b8

Browse files
Resolve SSW-307
This makes the MintLP redeemer path more efficient, which will minimize the impact on scoop costs. I also took some effort to convince myself in the comments above this branch that this (and other permutations) were safe, as this is the most likely (and most damaging) hack of a DEX, is finding some way to mint extra LP tokens.
1 parent 2487900 commit b6bc2b8

File tree

1 file changed

+19
-17
lines changed

1 file changed

+19
-17
lines changed

validators/pool.ak

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -447,27 +447,29 @@ validator(settings_policy_id: PolicyId) {
447447
pool_output_datum_correct,
448448
}
449449
}
450-
// when minting an LP token, we just need to make sure the pool NFT is present in one of the inputs,
451-
// meaning the pool script will enforce the correct name and quantity.
452-
//
453-
// Of particular note, you might expect this to fail when minting the initial LP tokens
454-
// but the minting policy only runs once, so it would be running with a different redeemer in that case
455-
// And it's not possible to include a *separate* minting redeemer to run the script twice; (TODO: check this)
456-
// even if it were, the pool token wouldn't be on the **inuputs** when we're minting the pool.
450+
// When minting an LP token, we just need to make sure the pool script is being spent, as it will enforce the correct
451+
// name and quantity of the LP tokens.
457452
//
458-
// It's also important that the pool script and the minting script checks that *no other* tokens of this policy are minted,
459-
// for example for a different pool. It should be ok if a token from a *different* policy is minted, though.
453+
// To do that, we could check for the pool NFT on the inputs, but this is expensive, especially if the pool input ends up being one of the last.
454+
// So instead we check that the pool NFT is in the first output (this is safe to assume because it's unique, and if it's in any other output it will fail)
455+
// and that we're not minting the pool token (i.e. someone could "pretend" to mint LP tokens, but also mint the pool token to make it look like a scoop)
456+
//
457+
// So, lets enumerate the possible cases:
458+
// - We use the CreatePool redeemer; this checks that *only* the correct pool token and correct number of LP tokens are minted
459+
// - We use the MintLP redeemer; this checks that the pool token (which is unique and locked in the pool script) is in the outputs, and not minted
460+
// - the pool script checks that only the correct number of LP tokens, and nothing else under this policy ID, are minted
461+
// And the impossible cases:
462+
// - During CreatePool, it would be impossible to mint multiple of the same pool tokens; a different pool token; a different number of LP tokens; or a different pool's LP tokens
463+
// - During MintLP, it would be impossible to mint the relevant pool token; thus, the pool script must run, and thus it will be impossible to mint another pool token, a different pool
464+
// ident pool token, a different quantity of LP tokens, or a different pools LP tokens
460465
MintLP(pool_ident) -> {
461466
expect Mint(own_policy_id) = ctx.purpose
462467
let pool_nft_name = shared.pool_nft_name(pool_ident)
463-
let allows_to_spend =
464-
fn(v) {
465-
value.quantity_of(v, own_policy_id, pool_nft_name) == 1
466-
}
467-
list.any(
468-
ctx.transaction.inputs,
469-
fn(input) { allows_to_spend(input.output.value) },
470-
)
468+
expect Some(pool_output) = list.head(ctx.transaction.outputs)
469+
and {
470+
(pool_output.value |> value.quantity_of(own_policy_id, pool_nft_name)) == 1,
471+
(ctx.transaction.mint |> value.from_minted_value |> value.quantity_of(own_policy_id, pool_nft_name)) == 0,
472+
}
471473
}
472474
}
473475
}

0 commit comments

Comments
 (0)