Skip to content

Commit

Permalink
Change the Address type in GlobalSetting to PoolAuthorizationMethod a…
Browse files Browse the repository at this point in the history
…nd do not allow Factory & Global Setting contains other assets
  • Loading branch information
h2physics committed Jun 3, 2024
1 parent 2d68760 commit 7bfa0d6
Show file tree
Hide file tree
Showing 11 changed files with 343 additions and 194 deletions.
57 changes: 13 additions & 44 deletions lib/amm_dex_v2/pool_validation.ak
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use aiken/dict.{Dict}
use aiken/hash.{Blake2b_224, Hash}
use aiken/list
use aiken/transaction.{Input, Output}
use aiken/transaction/credential.{
Address, Inline, PaymentCredential, ScriptCredential, StakeCredential,
VerificationKey, VerificationKeyCredential,
Address, PaymentCredential, ScriptCredential, StakeCredential,
VerificationKeyCredential,
}
use aiken/transaction/value.{
AssetName, PolicyId, Value, ada_asset_name, ada_policy_id,
}
use amm_dex_v2/types.{
Asset, BatchingPool, GlobalSetting, PoolDatum, UpdateDynamicFee, UpdatePoolFee,
Asset, BatchingPool, GlobalSetting, PAMSpendScript, PAMWithdrawScript,
PoolAuthorizationMethod, PoolDatum, UpdateDynamicFee, UpdatePoolFee,
UpdatePoolParametersAction, UpdatePoolStakeCredential,
}
use amm_dex_v2/utils
Expand Down Expand Up @@ -56,42 +55,6 @@ pub fn get_and_validate_global_setting(
global_setting_datum
}

pub fn authorize_license_holder(
license_address: Address,
transaction_inputs: List<Input>,
withdrawals: Dict<StakeCredential, Int>,
extra_signatories: List<Hash<Blake2b_224, VerificationKey>>,
) -> Bool {
let Address { payment_credential: license_holder_payment_cred, .. } =
license_address
when license_holder_payment_cred is {
//If the Authorizer is controlled by a PubKey wallet,
// the owners of the UTxO must sign the transaction with their private key. Otherwise, such action must be prohibited.
VerificationKeyCredential(pub_key_hash) ->
list.has(extra_signatories, pub_key_hash)
// If the Authorizer is controlled by a Script wallet,
// the smart contract must incorporate a Withdrawal or a Spend function and execute sufficient conditions to facilitate its operation
ScriptCredential(script_hash) -> {
let authorized_via_withdrawal =
dict.has_key(withdrawals, Inline(ScriptCredential(script_hash)))
if authorized_via_withdrawal {
True
} else {
list.any(
transaction_inputs,
fn(input) {
let Input { output, .. } = input
let Output { address: out_address, .. } = output
let Address { payment_credential: out_payment_credential, .. } =
out_address
out_payment_credential == license_holder_payment_cred
},
)
}
}
}
}

pub fn get_batching_pool(
stake_credential: StakeCredential,
pool_input: Output,
Expand Down Expand Up @@ -573,7 +536,7 @@ test test_get_trading_fee_numerator_fail_3() fail {
pub fn has_only_pool_and_author(
inputs: List<Input>,
pool_address: Address,
author_address: Address,
pool_author: PoolAuthorizationMethod,
) -> Bool {
let Address { payment_credential: pool_payment_cred, .. } = pool_address
// Having single pool input
Expand All @@ -598,8 +561,14 @@ pub fn has_only_pool_and_author(
let Input { output: Output { address: addr, .. }, .. } = input
let Address { payment_credential: payment_cred, .. } = addr
when payment_cred is {
ScriptCredential(_) ->
payment_cred == pool_payment_cred || addr == author_address
ScriptCredential(sh) -> or {
payment_cred == pool_payment_cred,
when pool_author is {
PAMSpendScript(author_hash) -> sh == author_hash
PAMWithdrawScript(author_hash) -> sh == author_hash
_ -> False
},
}
VerificationKeyCredential(_) -> True
}
},
Expand Down
18 changes: 12 additions & 6 deletions lib/amm_dex_v2/types.ak
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,12 @@ pub type AuthenRedeemer {
CreatePool
}

pub type PoolAuthorizationMethod {
PAMSignature { pub_key_hash: PubKeyHash }
PAMSpendScript { script_hash: ValidatorHash }
PAMWithdrawScript { script_hash: ValidatorHash }
}

pub type BatchingPool {
asset_a: Asset,
asset_b: Asset,
Expand All @@ -297,16 +303,16 @@ pub type PoolState =
// This setting grants permissions to authorized actors who can interact with Liquidity Pool features.
pub type GlobalSetting {
// List of authorized batchers who can process orders.
batchers: List<Address>,
batchers: List<PoolAuthorizationMethod>,
// The actor who can update the Pool's base fee and fee sharing.
pool_fee_updater: Address,
pool_fee_updater: PoolAuthorizationMethod,
// The actor who can withdraw the Pool's fee sharing.
fee_sharing_taker: Address,
fee_sharing_taker: PoolAuthorizationMethod,
// The actor who can change the Pool's stake key.
pool_stake_key_updater: Address,
pool_stake_key_updater: PoolAuthorizationMethod,
// The actor who can update the Pool's dynamic fee.
pool_dynamic_fee_updater: Address,
pool_dynamic_fee_updater: PoolAuthorizationMethod,
// The actor who can update the addresses mentioned above.
// This admin can be transferred to another wallet and should be stored in the most secure location.
admin: Address,
admin: PoolAuthorizationMethod,
}
105 changes: 100 additions & 5 deletions lib/amm_dex_v2/utils.ak
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
use aiken/builtin
use aiken/bytearray
use aiken/dict
use aiken/hash
use aiken/dict.{Dict}
use aiken/hash.{Blake2b_224, Hash}
use aiken/interval.{Finite, Interval, IntervalBound}
use aiken/list
use aiken/transaction.{Datum, DatumHash, InlineDatum, NoDatum, ValidityRange}
use aiken/transaction.{
Datum, DatumHash, InlineDatum, Input, NoDatum, Output, ValidityRange,
}
use aiken/transaction/credential.{
Address, Inline, ScriptCredential, StakeCredential, VerificationKey,
}
use aiken/transaction/value.{
AssetName, PolicyId, Value, ada_asset_name, ada_policy_id,
AssetName, MintedValue, PolicyId, Value, ada_asset_name, ada_policy_id,
}
use amm_dex_v2/types.{
Asset, DatumMap, OAMMintScript, OAMSignature, OAMSpendScript,
OAMWithdrawScript, OrderAuthorizationMethod, PAMSignature, PAMSpendScript,
PAMWithdrawScript, PoolAuthorizationMethod, SortedValueList,
}
use amm_dex_v2/types.{Asset, DatumMap, SortedValueList}

// the legitimate Pool TokenName
pub const pool_auth_asset_name = #"4d5350"
Expand Down Expand Up @@ -504,3 +513,89 @@ pub fn value_to_list(val: Value) -> SortedValueList {
},
)
}

// Pool Author can be one of 3 authorization methods
pub fn authorize_pool_license(
author: PoolAuthorizationMethod,
transaction_inputs: List<Input>,
withdrawals: Dict<StakeCredential, Int>,
extra_signatories: List<Hash<Blake2b_224, VerificationKey>>,
) -> Bool {
when author is {
// In case the wallet is a PubKey, its signature is required
PAMSignature(pub_key_hash) -> list.has(extra_signatories, pub_key_hash)
// In case the wallet is a Script and offer Spend method
// its Utxo has to present in the transaction inputs
PAMSpendScript(script_hash) -> {
let canceller_credential = ScriptCredential(script_hash)
!builtin.null_list(
list.filter(
transaction_inputs,
fn(input) {
let Input { output, .. } = input
let Output { address: out_address, .. } = output
let Address { payment_credential: out_payment_credential, .. } =
out_address
out_payment_credential == canceller_credential
},
),
)
}
// In case the wallet is a Script and offer Withdrawal method
// it has to make a withdrawal and present in transaction withdrawals
PAMWithdrawScript(script_hash) -> {
let credential = Inline(ScriptCredential(script_hash))
dict.has_key(withdrawals, credential)
}
}
}

// Canceller can be one of 4 authorization methods
pub fn authorize_order_license(
author: OrderAuthorizationMethod,
transaction_inputs: List<Input>,
withdrawals: Dict<StakeCredential, Int>,
extra_signatories: List<Hash<Blake2b_224, VerificationKey>>,
transaction_mint: MintedValue,
) -> Bool {
when author is {
// In case the wallet is a PubKey, its signature is required
OAMSignature(pub_key_hash) -> list.has(extra_signatories, pub_key_hash)
// In case the wallet is a Script and offer Spend method
// its Utxo has to present in the transaction inputs
OAMSpendScript(script_hash) -> {
let canceller_credential = ScriptCredential(script_hash)
!builtin.null_list(
list.filter(
transaction_inputs,
fn(input) {
let Input { output, .. } = input
let Output { address: out_address, .. } = output
let Address { payment_credential: out_payment_credential, .. } =
out_address
out_payment_credential == canceller_credential
},
),
)
}
// In case the wallet is a Script and offer Withdrawal method
// it has to make a withdrawal and present in transaction withdrawals
OAMWithdrawScript(script_hash) -> {
let credential = Inline(ScriptCredential(script_hash))
dict.has_key(withdrawals, credential)
}
// In case the wallet is a Script and offer Minting method
// it has to mint tokens that has defined policy id and present in transaction minting
// Token's quantity must not be zero
OAMMintScript(script_hash) -> {
let fst_token_quantity =
transaction_mint
|> value.from_minted_value()
|> value.tokens(script_hash)
|> dict.to_list()
|> builtin.head_list
|> builtin.snd_pair
fst_token_quantity != 0
}
}
}
78 changes: 58 additions & 20 deletions plutus.json

Large diffs are not rendered by default.

48 changes: 34 additions & 14 deletions src/batcher-sample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import { sha3 } from "./hash";
import { EmulatorProvider } from "./provider";
import { getContractScripts } from "./script";
import { ADA, Asset } from "./types/asset";
import { GlobalSetting } from "./types/global-setting";
import { GlobalSetting, PoolAuthorizationMethodType } from "./types/global-setting";
import { NetworkId } from "./types/network";
import {
AuthorizationMethodType,
OrderAuthorizationMethodType,
OrderAmountType,
OrderDatum,
OrderDirection,
Expand Down Expand Up @@ -239,16 +239,36 @@ function getGlobalSetting(lucid: Lucid): {
const pubkeyBatcher = getPubKeyBatcher();
const scriptBatcher = getScriptBatcher(lucid);
const globalSetting: GlobalSetting = {
batchers: [pubkeyBatcher.batcherAddr, scriptBatcher.batcherAddr],
admin: "addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc",
feeSharingTaker:
"addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc",
poolDynamicFeeUpdater:
"addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc",
poolFeeUpdater:
"addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc",
poolStakeKeyUpdater:
"addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc",
batchers: [
{
type: PoolAuthorizationMethodType.SIGNATURE,
hash: lucid.utils.paymentCredentialOf(pubkeyBatcher.batcherAddr).hash
},
{
type: PoolAuthorizationMethodType.SPEND_SCRIPT,
hash: lucid.utils.paymentCredentialOf(scriptBatcher.batcherAddr).hash
}
],
admin: {
type: PoolAuthorizationMethodType.SIGNATURE,
hash: lucid.utils.paymentCredentialOf("addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc").hash
},
feeSharingTaker: {
type: PoolAuthorizationMethodType.SIGNATURE,
hash: lucid.utils.paymentCredentialOf("addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc").hash
},
poolDynamicFeeUpdater: {
type: PoolAuthorizationMethodType.SIGNATURE,
hash: lucid.utils.paymentCredentialOf("addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc").hash
},
poolFeeUpdater: {
type: PoolAuthorizationMethodType.SIGNATURE,
hash: lucid.utils.paymentCredentialOf("addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc").hash
},
poolStakeKeyUpdater: {
type: PoolAuthorizationMethodType.SIGNATURE,
hash: lucid.utils.paymentCredentialOf("addr_test1vqe2eyupqj8e0jr8uumakm2zuhh2ucrcevy7hw8vztjaragvljjnc").hash
},
};
return {
globalSetting: globalSetting,
Expand Down Expand Up @@ -577,7 +597,7 @@ async function main(): Promise<void> {
const swapDirection = OrderDirection.A_TO_B;
const orderDatum: OrderDatum = {
canceller: {
type: AuthorizationMethodType.SIGNATURE,
type: OrderAuthorizationMethodType.SIGNATURE,
hash: cancellerPubKeyHash,
},
refundReceiver: testUserAddr,
Expand Down Expand Up @@ -616,7 +636,7 @@ async function main(): Promise<void> {

let tempDatumReserves: [bigint, bigint] = [amountA, amountB];
let tempValueReserves: [bigint, bigint] = [amountA, amountB];
for (let i = 0; i < 38; i++) {
for (let i = 0; i < 37; i++) {
const orderIn: UTxO = {
txHash:
"5573777bedba6bb5f56541681256158dcf8ebfbc9e7251277d25b118517dce10",
Expand Down
43 changes: 31 additions & 12 deletions src/types/global-setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,43 @@ import { Constr, Data } from "lucid-cardano";

import { AddressPlutusData } from "./address";

export enum PoolAuthorizationMethodType {
SIGNATURE = 0,
SPEND_SCRIPT,
WITHDRAW_SCRIPT,
}

export type PoolAuthorizationMethod = {
type: PoolAuthorizationMethodType,
hash: string;
}

export namespace PoolAuthorizationMethod {
export function toPlutus(m: PoolAuthorizationMethod): Constr<Data> {
return new Constr(m.type, [
m.hash
])
}
}

export type GlobalSetting = {
batchers: string[],
poolFeeUpdater: string,
feeSharingTaker: string,
poolStakeKeyUpdater: string,
poolDynamicFeeUpdater: string,
admin: string,
batchers: PoolAuthorizationMethod[],
poolFeeUpdater: PoolAuthorizationMethod,
feeSharingTaker: PoolAuthorizationMethod,
poolStakeKeyUpdater: PoolAuthorizationMethod,
poolDynamicFeeUpdater: PoolAuthorizationMethod,
admin: PoolAuthorizationMethod,
}

export namespace GlobalSetting {
export function toPlutus(gs: GlobalSetting): Constr<Data> {
return new Constr(0, [
gs.batchers.map(AddressPlutusData.toPlutus),
AddressPlutusData.toPlutus(gs.poolFeeUpdater),
AddressPlutusData.toPlutus(gs.feeSharingTaker),
AddressPlutusData.toPlutus(gs.poolStakeKeyUpdater),
AddressPlutusData.toPlutus(gs.poolDynamicFeeUpdater),
AddressPlutusData.toPlutus(gs.admin)
gs.batchers.map(PoolAuthorizationMethod.toPlutus),
PoolAuthorizationMethod.toPlutus(gs.poolFeeUpdater),
PoolAuthorizationMethod.toPlutus(gs.feeSharingTaker),
PoolAuthorizationMethod.toPlutus(gs.poolStakeKeyUpdater),
PoolAuthorizationMethod.toPlutus(gs.poolDynamicFeeUpdater),
PoolAuthorizationMethod.toPlutus(gs.admin)
])
}
}
Loading

0 comments on commit 7bfa0d6

Please sign in to comment.