Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Manage" pool stake script #80

Merged
merged 6 commits into from
Apr 12, 2024
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
8 changes: 8 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,17 @@ aiken blueprint apply -v settings.mint $PROTOCOL_BOOT_UTXO > tmp
mv tmp plutus.json

SETTINGS_SCRIPT_HASH="581c$(aiken blueprint policy -v settings.mint)"
aiken blueprint apply -v pool.manage $SETTINGS_SCRIPT_HASH > tmp
mv tmp plutus.json

MANAGE_STAKE_SCRIPT_HASH="581c$(aiken blueprint policy -v pool.manage)"
aiken blueprint apply -v pool.spend $MANAGE_STAKE_SCRIPT_HASH > tmp
mv tmp plutus.json
aiken blueprint apply -v pool.spend $SETTINGS_SCRIPT_HASH > tmp
mv tmp plutus.json

aiken blueprint apply -v pool.mint $MANAGE_STAKE_SCRIPT_HASH > tmp
mv tmp plutus.json
aiken blueprint apply -v pool.mint $SETTINGS_SCRIPT_HASH > tmp
mv tmp plutus.json

Expand Down
6 changes: 3 additions & 3 deletions lib/tests/examples/ex_pool.ak
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use types/pool.{PoolDatum, PoolRedeemer, PoolMintRedeemer, PoolScoop, WithdrawFees, CreatePool}
use types/pool.{PoolDatum, PoolRedeemer, PoolMintRedeemer, PoolScoop, ManageRedeemer, CreatePool, WithdrawFees}
use tests/examples/ex_shared.{print_example}

fn mk_pool_datum() -> PoolDatum {
Expand Down Expand Up @@ -33,8 +33,8 @@ test example_pool_scoop_redeemer() {
print_example(mk_pool_scoop())
}

pub fn mk_withdraw_fees_redeemer() -> PoolRedeemer {
WithdrawFees { amount: 100, treasury_output: 1 }
pub fn mk_withdraw_fees_redeemer() -> ManageRedeemer {
WithdrawFees { amount: 100, treasury_output: 1, pool_input: 0 }
}

test example_pool_withdraw_fees_redeemer() {
Expand Down
23 changes: 12 additions & 11 deletions lib/types/pool.ak
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,9 @@ pub type PoolRedeemer {
/// Much of the complexity of the protocol comes from ensuring this list is processed both efficiently and safely.
input_order: List<(Int, Option<SignedStrategyExecution>, Int)>,
}
/// Withdraw the earned protocol fees into the treasury
WithdrawFees {
/// The amount of earned protocol fees to withdraw
/// Note that we *don't* have to withdraw everything, to allow the minUTXO amount to be left behind on exotic pools.
amount: Int,
/// The index in the transaction outputs that corresponds to the treasury address
/// We do this to efficiently skip to that output,
/// and it is safe to do so because that output must be to the treasury address from the settings datum
treasury_output: Int,
}
UpdatePoolFees
/// Withdraw the earned protocol fees into the treasury, or update the pool
/// fees
Manage
}

/// We use the pool mint script for two different purposes
Expand Down Expand Up @@ -97,3 +89,12 @@ pub type PoolMintRedeemer {
/// to burn the pool NFT (when permitted by the spending validator)
BurnPool { identifier: Ident }
}

pub type ManageRedeemer {
WithdrawFees {
amount: Int,
treasury_output: Int,
pool_input: Int,
}
UpdatePoolFees { pool_input: Int, }
}
80 changes: 56 additions & 24 deletions lucid/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function settingsDatum(poolStakeHash: string, userPkh: string): string {
],
authorizedStakingKeys: [
{
VKeyCredential: { bytes: poolStakeHash },
SCredential: { bytes: poolStakeHash },
}
],
baseFee: 1000000n,
Expand Down Expand Up @@ -120,13 +120,15 @@ async function listOrder(lucid: Lucid, scripts: Scripts, userPkh: string, assets
},
scooperFee: scooperFee,
destination: {
address: {
paymentCredential: {
VKeyCredential: { bytes: userPkh },
Fixed: {
address: {
paymentCredential: {
VKeyCredential: { bytes: userPkh },
},
stakeCredential: null,
},
stakeCredential: null,
datum: "NoDatum",
},
datum: "NoDatum",
},
order: {
Swap: {
Expand Down Expand Up @@ -508,7 +510,9 @@ async function mintPool(scripts: Scripts, lucid: Lucid, userAddress: Address, se
identifier: toHex(poolId),
assets: assets,
circulatingLp: liq,
feesPer10Thousand: fees,
bidFeesPer10Thousand: fees,
askFeesPer10Thousand: fees,
feeManager: null,
marketOpen: marketOpen || 0n,
feeFinalized: marketOpen || 0n,
protocolFees: 2_000_000n,
Expand Down Expand Up @@ -536,6 +540,17 @@ async function mintPool(scripts: Scripts, lucid: Lucid, userAddress: Address, se
const poolMintRedeemerBytes = Data.to(poolMintRedeemer, types.PoolMintRedeemer);
const poolDatumBytes = Data.to(newPoolDatum, types.PoolDatum);

const poolAddress = (new Utils(lucid)).credentialToAddress(
{
type: "Script",
hash: scripts.poolScriptHash,
},
{
type: "Script",
hash: scripts.poolStakeHash,
}
);

console.log("value: ");
console.log(poolValue);
console.log("newPoolDatum: ");
Expand All @@ -544,6 +559,8 @@ async function mintPool(scripts: Scripts, lucid: Lucid, userAddress: Address, se
console.log(poolMintRedeemerBytes);
console.log("settings datum: ");
console.log(settings.datum);
console.log("pool address: ");
console.log(poolAddress);
console.log("-------");
console.log("seed: ", seed);
const tx = lucid.newTx()
Expand All @@ -554,15 +571,19 @@ async function mintPool(scripts: Scripts, lucid: Lucid, userAddress: Address, se
}, poolMintRedeemerBytes)
.readFrom([...references, settings])
.collectFrom([seed])
.payToContract(scripts.poolAddress, { inline: poolDatumBytes }, poolValue)
.payToContract(poolAddress, { inline: poolDatumBytes }, poolValue)
.payToAddress(userAddress, {
"lovelace": 2_000_000n,
[toUnit(scripts.poolPolicyId, poolLqNameHex)]: liq,
})
.payToAddress(userAddress, {
"lovelace": 2_000_000n,
[toUnit(scripts.poolPolicyId, poolRefNameHex)]: 1n,
});
.payToAddressWithData(
userAddress,
{ inline: "d87980" },
{
"lovelace": 2_000_000n,
[toUnit(scripts.poolPolicyId, poolRefNameHex)]: 1n,
}
);

const str = await tx.toString();
console.log("building tx: " + str);
Expand Down Expand Up @@ -644,8 +665,8 @@ async function testMintPool(lucid: Lucid, emulator: Emulator, scripts: Scripts,
const settings = settingsUtxos[0];

const minted = await mintPool(scripts, lucid, userAddress, settings, [refUtxo], assets, seed, 1_000_000_000n, 1_000_000_000n, [5n, 5n]);
await emulator.awaitTx(minted.mintedHash);
console.log("Minted a pool, hash: " + minted.mintedHash);
await emulator.awaitTx(minted.poolMintedHash);
console.log("Minted a pool, hash: " + minted.poolMintedHash);
return minted;
}

Expand Down Expand Up @@ -739,16 +760,16 @@ async function executeOrder(poolABL: ABL, poolDatum: types.PoolDatum, order: UTx
let res: ABL = { a: 0n, b: 0n, liq: 0n };
if ("Swap" in orderDatum.order) {
if (orderDatum.order.Swap.offer[0] + orderDatum.order.Swap.offer[1] == poolCoinA) {
[res, poolABL] = doSwap(Coin.CoinA, orderDatum.order.Swap.offer[2], poolDatum.feesPer10Thousand, poolABL);
[res, poolABL] = doSwap(Coin.CoinA, orderDatum.order.Swap.offer[2], poolDatum.bidFeesPer10Thousand, poolABL);
console.log("after swapping for coinA, poolABL will be: ");
console.log(poolABL);
} else if (orderDatum.order.Swap.offer[0] + orderDatum.order.Swap.offer[1] == poolCoinB) {
[res, poolABL] = doSwap(Coin.CoinB, orderDatum.order.Swap.offer[2], poolDatum.feesPer10Thousand, poolABL);
[res, poolABL] = doSwap(Coin.CoinB, orderDatum.order.Swap.offer[2], poolDatum.askFeesPer10Thousand, poolABL);
} else {
throw new Error("Order does not appear to match the pool");
}
}
const dest = await fromOrderDatumAddress(orderDatum.destination.address);
const dest = await fromOrderDatumAddress(orderDatum.destination.Fixed.address);
return [poolABL, {
abl: res,
destination: dest,
Expand Down Expand Up @@ -828,9 +849,9 @@ async function scoopPool(scripts: Scripts, lucid: Lucid, userAddress: Address, s
toSpend.push(...orderUtxos);
toSpend.sort((a, b) => a.txHash == b.txHash ? a.outputIndex - b.outputIndex : (a.txHash < b.txHash ? -1 : 1));
for (let e of toSpend) {
if (e.address == scripts.poolAddress) {
if (getAddressDetails(e.address).paymentCredential.hash == scripts.poolScriptHash) {
tx.collectFrom([e], redeemerData);
} else if (e.address == scripts.orderAddress) {
} else if (getAddressDetails(e.address).paymentCredential.hash == scripts.orderScriptHash) {
tx.collectFrom([e], Data.to(orderScoopRedeemer, types.OrderRedeemer));
} else {
tx.collectFrom([e]);
Expand All @@ -856,7 +877,7 @@ async function scoopPool(scripts: Scripts, lucid: Lucid, userAddress: Address, s
.addSigner(userAddress)
.withdraw(scripts.steakAddress, 0n, "00")

.payToContract(scripts.poolAddress, { inline: newPoolDatum }, {
.payToContract(targetPool.address, { inline: newPoolDatum }, {
"lovelace":
newPoolABL.a +
poolDatum.protocolFees,
Expand Down Expand Up @@ -920,7 +941,18 @@ async function testScoopPool(lucid: Lucid, emulator: Emulator, scripts: Scripts,
}
const settings = settingsUtxos[0];

let knownPools = await emulator.getUtxos(scripts.poolAddress);
const poolAddress = (new Utils(lucid)).credentialToAddress(
{
type: "Script",
hash: scripts.poolScriptHash,
},
{
type: "Script",
hash: scripts.poolStakeHash,
}
);

let knownPools = await emulator.getUtxos(poolAddress);

let targetPool = null;
for (let knownPool of knownPools) {
Expand Down Expand Up @@ -1060,8 +1092,8 @@ const accounts: any[] = [
];
let emulator = new Emulator(accounts, {
...PROTOCOL_PARAMETERS_DEFAULT,
//maxTxSize: 999999999999,
//maxTxExMem: 999999999999999n,
maxTxSize: 999999999999,
maxTxExMem: 999999999999999n,
});
let lucid = await Lucid.new(emulator);

Expand Down Expand Up @@ -1128,7 +1160,7 @@ emulator.ledger["000000000000000000000000000000000000000000000000000000000000000

const listOrdersChange = emulator.ledger["00000000000000000000000000000000000000000000000000000000000000001"].utxo;

const { listedHash, utxos: orders } =
const { listedHash, utxos: orders } =
await testListOrder(lucid, emulator, scripts, "lovelace", rberry, listOrdersChange, poolId, 40n);

const scoopPoolChange = await findChange(emulator, userAddress);
Expand Down
5 changes: 5 additions & 0 deletions lucid/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Make sure to build the aiken scripts first
deno run \
--allow-read \
main.ts \
--scriptsFile ../plutus.json
24 changes: 15 additions & 9 deletions lucid/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,17 @@ export const DatumSchema = Data.Enum([
//Data.Object({ InlineDatum: Data.Any() }),
]);

export const DestinationSchema = Data.Object({
address: AddressSchema,
datum: DatumSchema,
});
export const DestinationSchema = Data.Enum([
Data.Object({
Fixed: Data.Object({
address: AddressSchema,
datum: DatumSchema,
}),
}),
Data.Object({
Self: Data.Tuple([]),
}),
]);

export const ExtensionSchema = Data.Enum([
Data.Literal("NoExtension"),
Expand All @@ -139,7 +146,9 @@ export const PoolDatumSchema = Data.Object({
identifier: IdentSchema,
assets: Data.Tuple([AssetClassSchema, AssetClassSchema]),
circulatingLp: Data.Integer(),
feesPer10Thousand: Data.Tuple([Data.Integer(), Data.Integer()]),
bidFeesPer10Thousand: Data.Tuple([Data.Integer(), Data.Integer()]),
askFeesPer10Thousand: Data.Tuple([Data.Integer(), Data.Integer()]),
feeManager: Data.Nullable(MultiSigScriptSchema),
marketOpen: Data.Integer(),
feeFinalized: Data.Integer(),
protocolFees: Data.Integer(),
Expand Down Expand Up @@ -201,10 +210,7 @@ export const PoolSpendRedeemerSchema = Data.Enum([
}),
}),
Data.Object({
WithdrawFees: Data.Object({
amount: Data.Integer(),
treasuryOutput: Data.Integer(),
}),
Manage: Data.Tuple([]),
}),
]);

Expand Down
Loading
Loading