Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lib/deposit_utils.ak
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ pub fn list_foldl5(
when self is {
[] -> return(zero_a, zero_b, zero_c, zero_d, zero_e)
[x, ..xs] -> {
let acc_a, acc_b, acc_c, acc_d, acc_e <- with(x, zero_a, zero_b, zero_c, zero_d, zero_e)
let
acc_a,
acc_b,
acc_c,
acc_d,
acc_e,
<- with(x, zero_a, zero_b, zero_c, zero_d, zero_e)
list_foldl5(xs, acc_a, acc_b, acc_c, acc_d, acc_e, with, return)
}
}
Expand Down Expand Up @@ -157,7 +163,7 @@ pub fn process_batched_deposit_intent_validation(
// Extract Account from UserAccount and use as MPF key
expect UserTradeAccount { account: depositor_account, .. } =
depositor
let mpf_key = cbor.serialise(depositor_account)
let mpf_key = cbor.serialise(depositor)

// Track if depositor is operator
let new_cal_operator_shares_added =
Expand Down
7 changes: 1 addition & 6 deletions lib/price_oracle_utils.ak
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
use aiken/cbor
use aiken/collection/list
use aiken/collection/pairs
use aiken/math
use cardano/assets.{AssetName, PolicyId, Value}
use cardano/transaction.{Input}
use cocktail.{verify_signatures}
use types.{MValue, Message}

// Power of 10: returns 10^n
fn pow10(n: Int) -> Int {
math.pow(10, n)
}
use utils.{pow10}

pub fn verify_prices_oracle_messages(
prices_message: ByteArray,
Expand Down
27 changes: 16 additions & 11 deletions lib/types.ak
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ pub type MintPolarity {
RBurn
}

pub type VaultConfig {
// Config (all updatable via UpdateConfig)
app_oracle: PolicyId,
vault_script_hash: ByteArray,
l1_deposit_intent_script_hash: ByteArray,
l1_withdrawal_intent_script_hash: ByteArray,
l2_deposit_intent_script_hash: ByteArray,
l2_withdrawal_intent_script_hash: ByteArray,
pluggable_logic: ByteArray,
operator_account: UserAccount,
hydra_node_pub_keys: List<VerificationKey>,
}

// Vault Oracle Datum — holds config + state, commits to Hydra
pub type VaultOracleDatum {
// Config (all updatable via UpdateConfig)
Expand All @@ -26,8 +39,8 @@ pub type VaultOracleDatum {
pluggable_logic: ByteArray,
vault_stake_rotation_script_hash: ByteArray,
operator_account: UserAccount,
operator_charge_percentage: Int,
operator_min_deposit_percentage: Int,
operator_fee_rate_bp: Int,
operator_min_deposit_rate_bp: Int,
hydra_node_pub_keys: List<VerificationKey>,
is_active: Bool,
// State (mutable)
Expand All @@ -45,23 +58,15 @@ pub type VaultOracleMintRedeemer {
}

// Vault Oracle spend redeemer
// Note: L2InitialDeposit is handled by HydraAccount validator (ProcessVaultDeposit with total_shares == 0)
pub type VaultOracleSpendRedeemer {
L1InitialDeposit {
depositor: UserAccount,
initial_deposit: MValue,
prices_message: ByteArray,
signatures: List<ByteArray>,
initial_shares_proof: Proof,
}
ProcessL1Deposit
ProcessL1Withdrawal
ProcessL2Deposit
ProcessL2Withdrawal
HydraCommit
HydraDecommit
PluggableLogic
UpdateConfig
BurnVault
}

// Vault spend redeemer — fund management validator
Expand Down
40 changes: 39 additions & 1 deletion lib/utils.ak
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use aiken/crypto.{
ScriptHash, VerificationKey, VerificationKeyHash, blake2b_224,
verify_ed25519_signature,
}
use aiken/math
use cardano/address.{Credential, Script}
use cardano/assets.{Lovelace, PolicyId, Value, quantity_of}
use cardano/transaction.{InlineDatum, Input, Redeemer, ScriptPurpose}
use cocktail.{input_inline_datum}
use hydra_dex/types.{AppOracleDatum} as dd_types
use types.{
BurnIntent, BurnIntentL2, IntentRedeemerL1, IntentRedeemerL2, VaultOracleDatum,
BurnIntent, BurnIntentL2, IntentRedeemerL1, IntentRedeemerL2, VaultConfig,
VaultOracleDatum,
}

pub fn get_vault_oracle_datum(
Expand Down Expand Up @@ -42,6 +44,38 @@ pub fn get_vault_oracle_input(
oracle_input
}

pub fn get_vault_config(
inputs: List<Input>,
vault_oracle_nft: PolicyId,
) -> VaultConfig {
expect Some(oracle_input) =
inputs
|> list.find(
fn(input: Input) {
quantity_of(input.output.value, vault_oracle_nft, "") == 1
},
)

let datum = input_inline_datum(oracle_input)
if datum is VaultOracleDatum {
VaultConfig {
app_oracle: datum.app_oracle,
vault_script_hash: datum.vault_script_hash,
l1_deposit_intent_script_hash: datum.l1_deposit_intent_script_hash,
l1_withdrawal_intent_script_hash: datum.l1_withdrawal_intent_script_hash,
l2_deposit_intent_script_hash: datum.l2_deposit_intent_script_hash,
l2_withdrawal_intent_script_hash: datum.l2_withdrawal_intent_script_hash,
pluggable_logic: datum.pluggable_logic,
operator_account: datum.operator_account,
hydra_node_pub_keys: datum.hydra_node_pub_keys,
}
} else if datum is VaultConfig {
datum
} else {
fail @"Invalid datum type for vault oracle input"
}
}

pub fn get_app_oracle_datum(
reference_inputs: List<Input>,
oracle_nft: PolicyId,
Expand Down Expand Up @@ -158,3 +192,7 @@ pub fn validate_hydra_signatures_with_verification_key(
fn(key) { list.has(extra_signatories, crypto.blake2b_224(key)) },
)
}

pub fn pow10(n: Int) -> Int {
math.pow(10, n)
}
31 changes: 11 additions & 20 deletions lib/withdraw_utils.ak
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use aiken/cbor
use aiken/collection/list
use aiken/collection/pairs
use aiken/crypto.{ScriptHash}
use aiken/math
use aiken/merkle_patricia_forestry as mpf
use cardano/address.{Script}
use cardano/assets.{AssetName, PolicyId, Value}
Expand All @@ -13,11 +12,7 @@ use types.{
SharesDelete, SharesInsert, SharesMPFAction, SharesRecordEntry, SharesUpdate,
WithdrawalIntentDatum,
}

// Power of 10: returns 10^n
fn pow10(n: Int) -> Int {
math.pow(10, n)
}
use utils.{pow10}

pub type Scott6<a, b, c, d, e, f, result> =
fn(a, b, c, d, e, f) -> result
Expand Down Expand Up @@ -57,28 +52,23 @@ pub fn convert_shares_to_usd(
shares_amount * vault_equity / total_shares
}

// Round UP: ceil(a * b / c) = (a * b + c - 1) / c
fn ceil_div(numerator: Int, denominator: Int) -> Int {
( numerator + denominator - 1 ) / denominator
}

pub fn cal_per_user_operator_fee(
withdrawal_value: Int,
cost_basis: Int,
operator_charge_percentage: Int,
operator_fee_rate_bp: Int,
) -> Int {
let profit = withdrawal_value - cost_basis
if profit <= 0 {
0
} else {
// Round UP — fee never underpaid
ceil_div(profit * operator_charge_percentage, 100)
// Round DOWN — fee never overpaid
profit * operator_fee_rate_bp / 10000
}
}

pub fn compute_fee_shares(fee: Int, total_shares: Int, vault_equity: Int) -> Int {
// Round UP — protects operator
ceil_div(fee * total_shares, vault_equity)
// Round DOWN
fee * total_shares / vault_equity
}

// USD calculation: usd_value = Σ(amount * price / 10^scale) for each asset
Expand Down Expand Up @@ -108,7 +98,7 @@ pub fn process_batched_withdrawal_intent_validation(
mpf_actions: List<SharesMPFAction>,
vault_equity: Int,
total_shares: Int,
operator_charge_percentage: Int,
operator_fee_rate_bp: Int,
prices: Pairs<(PolicyId, AssetName), (Int, Int)>,
withdrawal_intent_script_hash: ScriptHash,
initial_merkle_root: ByteArray,
Expand Down Expand Up @@ -172,7 +162,7 @@ pub fn process_batched_withdrawal_intent_validation(
// Extract Account from UserAccount and use as MPF key
expect UserTradeAccount { account: withdrawer_acc, .. } =
withdrawer
let mpf_key = cbor.serialise(withdrawer_acc)
let mpf_key = cbor.serialise(withdrawer)

// Track if withdrawer is operator
let new_cal_operator_shares_withdrawn =
Expand Down Expand Up @@ -225,9 +215,10 @@ pub fn process_batched_withdrawal_intent_validation(
cal_per_user_operator_fee(
gross_value,
cost_basis,
operator_charge_percentage,
operator_fee_rate_bp,
)
let fs = compute_fee_shares(fee, total_shares, vault_equity)
let fs =
compute_fee_shares(fee, total_shares, vault_equity)
(fs, gross_value - fee)
}

Expand Down
230 changes: 46 additions & 184 deletions plutus.json

Large diffs are not rendered by default.

Loading
Loading