@indigo-labs/indigo-sdk 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +1 -0
- package/dist/index.d.mts +33 -14
- package/dist/index.d.ts +33 -14
- package/dist/index.js +80 -35
- package/dist/index.mjs +96 -43
- package/package.json +2 -2
- package/scripts/run-repeat.sh +22 -0
- package/src/contracts/stableswap/helpers.ts +139 -22
- package/src/contracts/stableswap/transactions.ts +15 -36
- package/tests/cdp/cdp.test.ts +1 -2
- package/tests/indigo-test-helpers.ts +2 -2
- package/tests/stableswap/stableswap-queries.ts +26 -17
- package/tests/stableswap/stableswap.test.ts +120 -8
package/dist/index.mjs
CHANGED
|
@@ -11250,7 +11250,11 @@ async function findCollateralAsset(lucid, sysParams, iassetName, collateralAsset
|
|
|
11250
11250
|
}
|
|
11251
11251
|
|
|
11252
11252
|
// src/contracts/stableswap/helpers.ts
|
|
11253
|
-
import {
|
|
11253
|
+
import {
|
|
11254
|
+
fromHex as fromHex19,
|
|
11255
|
+
fromText as fromText14,
|
|
11256
|
+
toHex as toHex19
|
|
11257
|
+
} from "@lucid-evolution/lucid";
|
|
11254
11258
|
import { array as A16, ord as Ord5, function as F27 } from "fp-ts";
|
|
11255
11259
|
|
|
11256
11260
|
// src/contracts/stableswap/types-new.ts
|
|
@@ -11355,10 +11359,15 @@ function parseStableswapOrderRedeemerOrThrow(redeemerCborHex) {
|
|
|
11355
11359
|
|
|
11356
11360
|
// src/contracts/stableswap/helpers.ts
|
|
11357
11361
|
import { Data as Data52 } from "@evolution-sdk/evolution";
|
|
11358
|
-
import {
|
|
11362
|
+
import {
|
|
11363
|
+
addressToBech32 as addressToBech323,
|
|
11364
|
+
assetClassValueOf as assetClassValueOf12,
|
|
11365
|
+
lovelacesAmt as lovelacesAmt5
|
|
11366
|
+
} from "@3rd-eye-labs/cardano-offchain-common";
|
|
11359
11367
|
var BASE_MAX_EXECUTION_FEE = 1620000n;
|
|
11360
|
-
var
|
|
11361
|
-
|
|
11368
|
+
var defaultPSMProcessingConfig = {
|
|
11369
|
+
enforceMaxExecutionFeeConstraint: true,
|
|
11370
|
+
enforceMinLovelaceConstraint: true
|
|
11362
11371
|
};
|
|
11363
11372
|
function createDestinationDatum(datum, outRef) {
|
|
11364
11373
|
if (!datum) {
|
|
@@ -11372,6 +11381,22 @@ function createDestinationDatum(datum, outRef) {
|
|
|
11372
11381
|
}
|
|
11373
11382
|
return Data52.toCBORHex(datum);
|
|
11374
11383
|
}
|
|
11384
|
+
function estimateMinOrderOutputLovelaces(lucid, orderDatum, orderAssets) {
|
|
11385
|
+
const expectedOutputLovelaces = estimateUtxoMinLovelace(
|
|
11386
|
+
lucid.config().protocolParameters,
|
|
11387
|
+
addressToBech323(orderDatum.destination, lucid.config().network),
|
|
11388
|
+
orderAssets,
|
|
11389
|
+
{
|
|
11390
|
+
kind: "inline",
|
|
11391
|
+
value: createDestinationDatum(orderDatum.destinationInlineDatum ?? null, {
|
|
11392
|
+
txHash: "0000000000000000000000000000000000000000000000000000000000000000",
|
|
11393
|
+
outputIndex: 0
|
|
11394
|
+
})
|
|
11395
|
+
}
|
|
11396
|
+
);
|
|
11397
|
+
const roundedExpectedOutputLovelaces = (expectedOutputLovelaces / 1000000n + 1n) * 1000000n;
|
|
11398
|
+
return roundedExpectedOutputLovelaces;
|
|
11399
|
+
}
|
|
11375
11400
|
function psmOrderType(order, sysParams) {
|
|
11376
11401
|
const iassetAc = {
|
|
11377
11402
|
currencySymbol: fromHex19(
|
|
@@ -11387,28 +11412,56 @@ function psmOrderType(order, sysParams) {
|
|
|
11387
11412
|
if (suppliedIasset != 0n && suppliedCollateralAsset != 0n || suppliedIasset == 0n && suppliedCollateralAsset == 0n) {
|
|
11388
11413
|
return {
|
|
11389
11414
|
type: "ERROR",
|
|
11415
|
+
errorTag: "VALUE_ERROR",
|
|
11390
11416
|
reason: "An order must supply either iAsset or collateral asset"
|
|
11391
11417
|
};
|
|
11392
11418
|
}
|
|
11393
11419
|
const isMinting = suppliedCollateralAsset > 0n;
|
|
11394
11420
|
return isMinting ? { type: "MINTING", suppliedCollateral: suppliedCollateralAsset } : { type: "REDEEMING", suppliedIassets: suppliedIasset };
|
|
11395
11421
|
}
|
|
11396
|
-
function summariseOrder(order, psmPool, sysParams,
|
|
11422
|
+
function summariseOrder(lucid, order, psmPool, sysParams, psmProcessingConfig) {
|
|
11423
|
+
const config = {
|
|
11424
|
+
...defaultPSMProcessingConfig,
|
|
11425
|
+
...psmProcessingConfig
|
|
11426
|
+
};
|
|
11397
11427
|
const orderType = psmOrderType(order, sysParams);
|
|
11398
11428
|
if (orderType.type === "ERROR") {
|
|
11399
|
-
return {
|
|
11429
|
+
return {
|
|
11430
|
+
_tag: "ERROR",
|
|
11431
|
+
errorTag: orderType.errorTag,
|
|
11432
|
+
description: orderType.reason
|
|
11433
|
+
};
|
|
11434
|
+
}
|
|
11435
|
+
if (toHex19(order.datum.iasset) !== toHex19(psmPool.datum.iasset) || toHex19(order.datum.collateralAsset.currencySymbol) !== toHex19(psmPool.datum.collateralAsset.currencySymbol) || toHex19(order.datum.collateralAsset.tokenName) !== toHex19(psmPool.datum.collateralAsset.tokenName)) {
|
|
11436
|
+
return {
|
|
11437
|
+
_tag: "ERROR",
|
|
11438
|
+
errorTag: "ASSET_MISMATCH",
|
|
11439
|
+
description: "Order - PSM assets mismatch"
|
|
11440
|
+
};
|
|
11400
11441
|
}
|
|
11401
11442
|
const isOneToOne = psmPool.datum.collateralToIassetRatio.numerator === psmPool.datum.collateralToIassetRatio.denominator;
|
|
11402
|
-
if (
|
|
11443
|
+
if (config.enforceMaxExecutionFeeConstraint && order.datum.maxExecutionFee < BASE_MAX_EXECUTION_FEE) {
|
|
11444
|
+
return {
|
|
11445
|
+
_tag: "ERROR",
|
|
11446
|
+
errorTag: "EXECUTION_FEE",
|
|
11447
|
+
description: `Max execution fee is too low. Minimum: ${BASE_MAX_EXECUTION_FEE}`
|
|
11448
|
+
};
|
|
11449
|
+
}
|
|
11450
|
+
if (config.enforceMinLovelaceConstraint && lovelacesAmt5(order.utxo.assets) < estimateMinOrderOutputLovelaces(lucid, order.datum, order.utxo.assets) + order.datum.maxExecutionFee) {
|
|
11403
11451
|
return {
|
|
11404
11452
|
_tag: "ERROR",
|
|
11405
|
-
|
|
11453
|
+
errorTag: "INSUFFICIENT_LOVELACES",
|
|
11454
|
+
description: "Order has insufficient lovelaces to cover execution fee and order output."
|
|
11406
11455
|
};
|
|
11407
11456
|
}
|
|
11408
11457
|
if (orderType.type === "MINTING") {
|
|
11409
11458
|
const suppliedCollateralAsset = orderType.suppliedCollateral;
|
|
11410
11459
|
if (rationalToFloat(order.datum.maxFeeRatio) < rationalToFloat(psmPool.datum.mintingFeeRatio)) {
|
|
11411
|
-
return {
|
|
11460
|
+
return {
|
|
11461
|
+
_tag: "ERROR",
|
|
11462
|
+
errorTag: "MAX_FEE",
|
|
11463
|
+
description: "Max fee ratio not satisfied"
|
|
11464
|
+
};
|
|
11412
11465
|
}
|
|
11413
11466
|
if (isOneToOne) {
|
|
11414
11467
|
const fee = calculateFeeFromRatio(
|
|
@@ -11472,7 +11525,11 @@ function summariseOrder(order, psmPool, sysParams, orderProcessingConfig) {
|
|
|
11472
11525
|
} else {
|
|
11473
11526
|
const suppliedIasset = orderType.suppliedIassets;
|
|
11474
11527
|
if (rationalToFloat(order.datum.maxFeeRatio) < rationalToFloat(psmPool.datum.redemptionFeeRatio)) {
|
|
11475
|
-
return {
|
|
11528
|
+
return {
|
|
11529
|
+
_tag: "ERROR",
|
|
11530
|
+
errorTag: "MAX_FEE",
|
|
11531
|
+
description: "Max fee ratio not satisfied"
|
|
11532
|
+
};
|
|
11476
11533
|
}
|
|
11477
11534
|
const fee = calculateFeeFromRatio(
|
|
11478
11535
|
psmPool.datum.redemptionFeeRatio,
|
|
@@ -11537,14 +11594,20 @@ function summariseOrder(order, psmPool, sysParams, orderProcessingConfig) {
|
|
|
11537
11594
|
}
|
|
11538
11595
|
}
|
|
11539
11596
|
}
|
|
11540
|
-
function pickValidSatisfiableOrders(orders, pool, sysParams,
|
|
11597
|
+
function pickValidSatisfiableOrders(lucid, orders, pool, sysParams, psmProcessingConfig) {
|
|
11541
11598
|
const psmAvailableLiq = assetClassValueOf12(
|
|
11542
11599
|
pool.utxo.assets,
|
|
11543
11600
|
pool.datum.collateralAsset
|
|
11544
11601
|
);
|
|
11545
11602
|
const validOrders = orders.flatMap((order) => {
|
|
11546
11603
|
try {
|
|
11547
|
-
const res = summariseOrder(
|
|
11604
|
+
const res = summariseOrder(
|
|
11605
|
+
lucid,
|
|
11606
|
+
order,
|
|
11607
|
+
pool,
|
|
11608
|
+
sysParams,
|
|
11609
|
+
psmProcessingConfig
|
|
11610
|
+
);
|
|
11548
11611
|
return res._tag === "SUCCESS" ? [res.result] : [];
|
|
11549
11612
|
} catch (_) {
|
|
11550
11613
|
return [];
|
|
@@ -11605,16 +11668,16 @@ import {
|
|
|
11605
11668
|
fromText as fromText15,
|
|
11606
11669
|
paymentCredentialOf as paymentCredentialOf3,
|
|
11607
11670
|
sortUTxOs as sortUTxOs2,
|
|
11608
|
-
toHex as
|
|
11671
|
+
toHex as toHex20
|
|
11609
11672
|
} from "@lucid-evolution/lucid";
|
|
11610
11673
|
import {
|
|
11611
11674
|
addressFromBech32 as addressFromBech323,
|
|
11612
|
-
addressToBech32 as
|
|
11675
|
+
addressToBech32 as addressToBech324,
|
|
11613
11676
|
getInlineDatumOrThrow as getInlineDatumOrThrow6,
|
|
11614
11677
|
matchSingle as matchSingle7,
|
|
11615
11678
|
mkAssetsOf as mkAssetsOf16,
|
|
11616
11679
|
mkLovelacesOf as mkLovelacesOf9,
|
|
11617
|
-
lovelacesAmt as
|
|
11680
|
+
lovelacesAmt as lovelacesAmt6,
|
|
11618
11681
|
isSameOutRef as isSameOutRef2,
|
|
11619
11682
|
assetClassValueOf as assetClassValueOf13
|
|
11620
11683
|
} from "@3rd-eye-labs/cardano-offchain-common";
|
|
@@ -11641,19 +11704,16 @@ async function createStableswapOrder(iasset, collateralAsset, amount, minting, p
|
|
|
11641
11704
|
},
|
|
11642
11705
|
amount
|
|
11643
11706
|
);
|
|
11644
|
-
const
|
|
11645
|
-
lucid.config().protocolParameters,
|
|
11646
|
-
myAddress,
|
|
11707
|
+
const orderAssetsPlusFees = addAssets18(
|
|
11647
11708
|
assetsToSwap,
|
|
11648
|
-
|
|
11649
|
-
|
|
11650
|
-
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
|
|
11654
|
-
|
|
11709
|
+
mkLovelacesOf9(maxExecutionFee),
|
|
11710
|
+
mkLovelacesOf9(additionalLovelaces)
|
|
11711
|
+
);
|
|
11712
|
+
const expectedMinOutputLovelaces = estimateMinOrderOutputLovelaces(
|
|
11713
|
+
lucid,
|
|
11714
|
+
datum,
|
|
11715
|
+
orderAssetsPlusFees
|
|
11655
11716
|
);
|
|
11656
|
-
const roundedExpectedOutputLovelaces = (expectedOutputLovelaces / 1000000n + 1n) * 1000000n;
|
|
11657
11717
|
return lucid.newTx().pay.ToContract(
|
|
11658
11718
|
credentialToAddress6(lucid.config().network, {
|
|
11659
11719
|
hash: params.validatorHashes.stableswapHash,
|
|
@@ -11663,12 +11723,7 @@ async function createStableswapOrder(iasset, collateralAsset, amount, minting, p
|
|
|
11663
11723
|
kind: "inline",
|
|
11664
11724
|
value: serialiseStableswapOrderDatum(datum)
|
|
11665
11725
|
},
|
|
11666
|
-
addAssets18(
|
|
11667
|
-
assetsToSwap,
|
|
11668
|
-
mkLovelacesOf9(
|
|
11669
|
-
roundedExpectedOutputLovelaces + maxExecutionFee + additionalLovelaces
|
|
11670
|
-
)
|
|
11671
|
-
)
|
|
11726
|
+
addAssets18(orderAssetsPlusFees, mkLovelacesOf9(expectedMinOutputLovelaces))
|
|
11672
11727
|
);
|
|
11673
11728
|
}
|
|
11674
11729
|
async function cancelStableswapOrder(stableswapOrderOref, sysParams, lucid) {
|
|
@@ -11690,9 +11745,9 @@ async function cancelStableswapOrder(stableswapOrderOref, sysParams, lucid) {
|
|
|
11690
11745
|
return lucid.newTx().readFrom([stableswapScriptRefUtxo]).collectFrom(
|
|
11691
11746
|
[stableswapOrderUtxo],
|
|
11692
11747
|
serialiseStableswapOrderRedeemer("CancelStableswapOrder")
|
|
11693
|
-
).addSignerKey(
|
|
11748
|
+
).addSignerKey(toHex20(stableswapOrderDatum.owner));
|
|
11694
11749
|
}
|
|
11695
|
-
async function batchProcessStableswapOrders(stableswapOrderOrefs, stableswapPoolOref, treasuryOref, sysParams, lucid,
|
|
11750
|
+
async function batchProcessStableswapOrders(stableswapOrderOrefs, stableswapPoolOref, treasuryOref, sysParams, lucid, psmProcessingConfig) {
|
|
11696
11751
|
const stableswapScriptRefUtxo = matchSingle7(
|
|
11697
11752
|
await lucid.utxosByOutRef([
|
|
11698
11753
|
fromSystemParamsScriptRef(
|
|
@@ -11749,17 +11804,15 @@ async function batchProcessStableswapOrders(stableswapOrderOrefs, stableswapPool
|
|
|
11749
11804
|
const orderDatum = parseStableswapOrderDatumOrThrow(
|
|
11750
11805
|
getInlineDatumOrThrow6(orderUtxo)
|
|
11751
11806
|
);
|
|
11752
|
-
if (toHex19(orderDatum.iasset) != toHex19(mainOrderDatum.iasset) || toHex19(orderDatum.collateralAsset.currencySymbol) != toHex19(mainOrderDatum.collateralAsset.currencySymbol) || toHex19(orderDatum.collateralAsset.tokenName) != toHex19(mainOrderDatum.collateralAsset.tokenName)) {
|
|
11753
|
-
throw new Error("Wrong batch of orders");
|
|
11754
|
-
}
|
|
11755
11807
|
const res = summariseOrder(
|
|
11808
|
+
lucid,
|
|
11756
11809
|
{ utxo: orderUtxo, datum: orderDatum },
|
|
11757
11810
|
{ utxo: stableswapPoolUtxo, datum: stableswapPoolDatum },
|
|
11758
11811
|
sysParams,
|
|
11759
|
-
|
|
11812
|
+
psmProcessingConfig
|
|
11760
11813
|
);
|
|
11761
11814
|
if (res._tag === "ERROR") {
|
|
11762
|
-
throw new Error(res.
|
|
11815
|
+
throw new Error(res.description);
|
|
11763
11816
|
}
|
|
11764
11817
|
return res.result;
|
|
11765
11818
|
}
|
|
@@ -11838,7 +11891,7 @@ async function batchProcessStableswapOrders(stableswapOrderOrefs, stableswapPool
|
|
|
11838
11891
|
inputs: [orderInfo.order.utxo, mainOrderUtxo]
|
|
11839
11892
|
}
|
|
11840
11893
|
).pay.ToAddressWithData(
|
|
11841
|
-
|
|
11894
|
+
addressToBech324(
|
|
11842
11895
|
orderInfo.order.datum.destination,
|
|
11843
11896
|
lucid.config().network
|
|
11844
11897
|
),
|
|
@@ -11853,7 +11906,7 @@ async function batchProcessStableswapOrders(stableswapOrderOrefs, stableswapPool
|
|
|
11853
11906
|
// NOTICE: Currently, we always take the max execution fee from the order utxo.
|
|
11854
11907
|
// This can be improved so that we take the actual execution fee.
|
|
11855
11908
|
mkLovelacesOf9(
|
|
11856
|
-
|
|
11909
|
+
lovelacesAmt6(orderInfo.order.utxo.assets) - orderInfo.order.datum.maxExecutionFee
|
|
11857
11910
|
),
|
|
11858
11911
|
orderInfo.orderType === "MINTING" ? mkAssetsOf16(iassetAc, orderInfo.swapInfo.owedIasset) : mkAssetsOf16(
|
|
11859
11912
|
collateralAc,
|
|
@@ -11929,7 +11982,7 @@ async function updateStableswapPoolFees(stableswapPoolOutRef, stableswapFeeOutRe
|
|
|
11929
11982
|
value: serialiseStableswapPoolDatum(newStableswapPoolDatum)
|
|
11930
11983
|
},
|
|
11931
11984
|
stableswapPool.assets
|
|
11932
|
-
).addSignerKey(
|
|
11985
|
+
).addSignerKey(toHex20(stableswapPoolDatum.feeManager)).setMinFee(1038402n);
|
|
11933
11986
|
}
|
|
11934
11987
|
export {
|
|
11935
11988
|
AccountContentSchema,
|
|
@@ -12049,7 +12102,6 @@ export {
|
|
|
12049
12102
|
createStableswapOrder,
|
|
12050
12103
|
decodePriceUpdate,
|
|
12051
12104
|
decodePythMessage,
|
|
12052
|
-
defaultOrderProcessingConfig,
|
|
12053
12105
|
depositCdp,
|
|
12054
12106
|
deriveAuthToken,
|
|
12055
12107
|
derivePythPrice,
|
|
@@ -12061,6 +12113,7 @@ export {
|
|
|
12061
12113
|
encodePythMessage,
|
|
12062
12114
|
encodeSignedPythMessage,
|
|
12063
12115
|
endProposal,
|
|
12116
|
+
estimateMinOrderOutputLovelaces,
|
|
12064
12117
|
estimateUtxoMinLovelace,
|
|
12065
12118
|
executeProposal,
|
|
12066
12119
|
feedInterestOracle,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indigo-labs/indigo-sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Indigo SDK for interacting with Indigo endpoints via lucid-evolution",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@3rd-eye-labs/cardano-offchain-common": "1.4.7",
|
|
32
32
|
"@evolution-sdk/evolution": "^0.3.22",
|
|
33
33
|
"@harmoniclabs/crypto": "^0.3.0",
|
|
34
|
-
"@lucid-evolution/lucid": "0.6.
|
|
34
|
+
"@lucid-evolution/lucid": "0.6.1",
|
|
35
35
|
"@noble/ed25519": "^3.0.0",
|
|
36
36
|
"@pythnetwork/pyth-lazer-sdk": "^6.0.0",
|
|
37
37
|
"decimal.js": "^10.6.0",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Usage: ./scripts/run-repeat.sh <n> <command...>
|
|
3
|
+
# Example: ./scripts/run-repeat.sh 100 pnpm test stableswap.test.ts
|
|
4
|
+
|
|
5
|
+
N=${1:?Usage: $0 <n> <command...>}
|
|
6
|
+
shift
|
|
7
|
+
CMD=("$@")
|
|
8
|
+
|
|
9
|
+
failures=0
|
|
10
|
+
|
|
11
|
+
for ((i = 1; i <= N; i++)); do
|
|
12
|
+
printf "Run %d/%d ... " "$i" "$N"
|
|
13
|
+
if "${CMD[@]}" > /tmp/run-repeat-out.txt 2>&1; then
|
|
14
|
+
echo "ok"
|
|
15
|
+
else
|
|
16
|
+
echo "FAILED"
|
|
17
|
+
((failures++))
|
|
18
|
+
fi
|
|
19
|
+
done
|
|
20
|
+
|
|
21
|
+
echo ""
|
|
22
|
+
echo "Done: $((N - failures))/$N passed, $failures failed."
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Assets,
|
|
3
|
+
fromHex,
|
|
4
|
+
fromText,
|
|
5
|
+
LucidEvolution,
|
|
6
|
+
OutRef,
|
|
7
|
+
toHex,
|
|
8
|
+
} from '@lucid-evolution/lucid';
|
|
2
9
|
import { array as A, ord as Ord, function as F } from 'fp-ts';
|
|
3
10
|
import {
|
|
4
11
|
serialiseStableswapOutputDatum,
|
|
@@ -6,7 +13,11 @@ import {
|
|
|
6
13
|
} from './types-new';
|
|
7
14
|
import { Data } from '@evolution-sdk/evolution';
|
|
8
15
|
import { ParsedOutput } from '../../types/generic';
|
|
9
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
addressToBech32,
|
|
18
|
+
assetClassValueOf,
|
|
19
|
+
lovelacesAmt,
|
|
20
|
+
} from '@3rd-eye-labs/cardano-offchain-common';
|
|
10
21
|
import { SystemParams } from '../../types/system-params';
|
|
11
22
|
import { StableswapPoolContent } from '../cdp/types-new';
|
|
12
23
|
import { calculateFeeFromRatio } from '../../utils/indigo-helpers';
|
|
@@ -18,22 +29,30 @@ import {
|
|
|
18
29
|
rationalToFloat,
|
|
19
30
|
} from '../../types/rational';
|
|
20
31
|
import { BigIntOrd } from '../../utils/bigint-utils';
|
|
32
|
+
import { estimateUtxoMinLovelace } from '../../utils/lucid-utils';
|
|
21
33
|
|
|
22
34
|
export const BASE_MAX_EXECUTION_FEE = 1_620_000n;
|
|
23
35
|
|
|
24
|
-
export type
|
|
36
|
+
export type PSMProcessingConfig = {
|
|
25
37
|
/**
|
|
26
|
-
* Whether to
|
|
27
|
-
*
|
|
38
|
+
* Whether to enforce that an order has max execution fee satisfying
|
|
39
|
+
* min threshold (i.e. the processor might be paying the remaining cardano tx fee).
|
|
28
40
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
41
|
+
* In case, owner wants to process such order himself, he can ignore the constraint.
|
|
42
|
+
* @default true
|
|
31
43
|
*/
|
|
32
|
-
|
|
44
|
+
enforceMaxExecutionFeeConstraint?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Whether to enforce the minimum lovelace constraint. If not enforced,
|
|
47
|
+
* the processor might need to pay the min lovelace for the order output.
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
enforceMinLovelaceConstraint?: boolean;
|
|
33
51
|
};
|
|
34
52
|
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
const defaultPSMProcessingConfig: PSMProcessingConfig = {
|
|
54
|
+
enforceMaxExecutionFeeConstraint: true,
|
|
55
|
+
enforceMinLovelaceConstraint: true,
|
|
37
56
|
};
|
|
38
57
|
|
|
39
58
|
export function createDestinationDatum(
|
|
@@ -68,6 +87,39 @@ export type StableswapOrderInfo = {
|
|
|
68
87
|
swapInfo: StableswapInfo;
|
|
69
88
|
};
|
|
70
89
|
|
|
90
|
+
/**
|
|
91
|
+
* This is an approximation of the amount of lovelace that will be needed to pay for the output.
|
|
92
|
+
*/
|
|
93
|
+
export function estimateMinOrderOutputLovelaces(
|
|
94
|
+
lucid: LucidEvolution,
|
|
95
|
+
orderDatum: StableswapOrderDatum,
|
|
96
|
+
/**
|
|
97
|
+
* Including execution fee as well.
|
|
98
|
+
*/
|
|
99
|
+
orderAssets: Assets,
|
|
100
|
+
): bigint {
|
|
101
|
+
const expectedOutputLovelaces = estimateUtxoMinLovelace(
|
|
102
|
+
lucid.config().protocolParameters!,
|
|
103
|
+
addressToBech32(orderDatum.destination, lucid.config().network!),
|
|
104
|
+
orderAssets,
|
|
105
|
+
{
|
|
106
|
+
kind: 'inline',
|
|
107
|
+
value: createDestinationDatum(orderDatum.destinationInlineDatum ?? null, {
|
|
108
|
+
txHash:
|
|
109
|
+
'0000000000000000000000000000000000000000000000000000000000000000',
|
|
110
|
+
outputIndex: 0,
|
|
111
|
+
}),
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const roundedExpectedOutputLovelaces =
|
|
116
|
+
(expectedOutputLovelaces / 1_000_000n + 1n) * 1_000_000n;
|
|
117
|
+
|
|
118
|
+
return roundedExpectedOutputLovelaces;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type OrderTypeError = 'VALUE_ERROR';
|
|
122
|
+
|
|
71
123
|
/**
|
|
72
124
|
* Determine the PSM order type.
|
|
73
125
|
*/
|
|
@@ -77,7 +129,7 @@ export function psmOrderType(
|
|
|
77
129
|
):
|
|
78
130
|
| { type: 'MINTING'; suppliedCollateral: bigint }
|
|
79
131
|
| { type: 'REDEEMING'; suppliedIassets: bigint }
|
|
80
|
-
| { type: 'ERROR'; reason: string } {
|
|
132
|
+
| { type: 'ERROR'; errorTag: OrderTypeError; reason: string } {
|
|
81
133
|
const iassetAc = {
|
|
82
134
|
currencySymbol: fromHex(
|
|
83
135
|
sysParams.stableswapParams.iassetSymbol.unCurrencySymbol,
|
|
@@ -97,6 +149,7 @@ export function psmOrderType(
|
|
|
97
149
|
) {
|
|
98
150
|
return {
|
|
99
151
|
type: 'ERROR',
|
|
152
|
+
errorTag: 'VALUE_ERROR',
|
|
100
153
|
reason: 'An order must supply either iAsset or collateral asset',
|
|
101
154
|
};
|
|
102
155
|
}
|
|
@@ -108,36 +161,84 @@ export function psmOrderType(
|
|
|
108
161
|
: { type: 'REDEEMING', suppliedIassets: suppliedIasset };
|
|
109
162
|
}
|
|
110
163
|
|
|
164
|
+
type SummaryError =
|
|
165
|
+
| OrderTypeError
|
|
166
|
+
| 'ASSET_MISMATCH'
|
|
167
|
+
| 'EXECUTION_FEE'
|
|
168
|
+
| 'MAX_FEE'
|
|
169
|
+
| 'INSUFFICIENT_LOVELACES';
|
|
170
|
+
|
|
111
171
|
type SummaryResult =
|
|
112
172
|
| { _tag: 'SUCCESS'; result: StableswapOrderInfo }
|
|
113
|
-
| { _tag: 'ERROR';
|
|
173
|
+
| { _tag: 'ERROR'; errorTag: SummaryError; description: string };
|
|
114
174
|
|
|
115
175
|
/**
|
|
116
|
-
* Summarise the order
|
|
176
|
+
* Summarise the order. Validate all the necessary constraints
|
|
177
|
+
* for this order to be processed.
|
|
117
178
|
*/
|
|
118
179
|
export function summariseOrder(
|
|
180
|
+
lucid: LucidEvolution,
|
|
119
181
|
order: ParsedOutput<StableswapOrderDatum>,
|
|
120
182
|
psmPool: ParsedOutput<StableswapPoolContent>,
|
|
121
183
|
sysParams: SystemParams,
|
|
122
|
-
|
|
184
|
+
psmProcessingConfig?: PSMProcessingConfig,
|
|
123
185
|
): SummaryResult {
|
|
186
|
+
const config = {
|
|
187
|
+
...defaultPSMProcessingConfig,
|
|
188
|
+
...psmProcessingConfig,
|
|
189
|
+
} satisfies PSMProcessingConfig;
|
|
190
|
+
|
|
124
191
|
const orderType = psmOrderType(order, sysParams);
|
|
125
192
|
|
|
126
193
|
if (orderType.type === 'ERROR') {
|
|
127
|
-
return {
|
|
194
|
+
return {
|
|
195
|
+
_tag: 'ERROR',
|
|
196
|
+
errorTag: orderType.errorTag,
|
|
197
|
+
description: orderType.reason,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (
|
|
202
|
+
toHex(order.datum.iasset) !== toHex(psmPool.datum.iasset) ||
|
|
203
|
+
toHex(order.datum.collateralAsset.currencySymbol) !==
|
|
204
|
+
toHex(psmPool.datum.collateralAsset.currencySymbol) ||
|
|
205
|
+
toHex(order.datum.collateralAsset.tokenName) !==
|
|
206
|
+
toHex(psmPool.datum.collateralAsset.tokenName)
|
|
207
|
+
) {
|
|
208
|
+
return {
|
|
209
|
+
_tag: 'ERROR',
|
|
210
|
+
errorTag: 'ASSET_MISMATCH',
|
|
211
|
+
description: 'Order - PSM assets mismatch',
|
|
212
|
+
};
|
|
128
213
|
}
|
|
129
214
|
|
|
130
215
|
const isOneToOne =
|
|
131
216
|
psmPool.datum.collateralToIassetRatio.numerator ===
|
|
132
217
|
psmPool.datum.collateralToIassetRatio.denominator;
|
|
133
218
|
|
|
219
|
+
// TODO: check that the order has enough funds.
|
|
134
220
|
if (
|
|
135
|
-
|
|
221
|
+
config.enforceMaxExecutionFeeConstraint &&
|
|
136
222
|
order.datum.maxExecutionFee < BASE_MAX_EXECUTION_FEE
|
|
137
223
|
) {
|
|
138
224
|
return {
|
|
139
225
|
_tag: 'ERROR',
|
|
140
|
-
|
|
226
|
+
errorTag: 'EXECUTION_FEE',
|
|
227
|
+
description: `Max execution fee is too low. Minimum: ${BASE_MAX_EXECUTION_FEE}`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (
|
|
232
|
+
config.enforceMinLovelaceConstraint &&
|
|
233
|
+
lovelacesAmt(order.utxo.assets) <
|
|
234
|
+
estimateMinOrderOutputLovelaces(lucid, order.datum, order.utxo.assets) +
|
|
235
|
+
order.datum.maxExecutionFee
|
|
236
|
+
) {
|
|
237
|
+
return {
|
|
238
|
+
_tag: 'ERROR',
|
|
239
|
+
errorTag: 'INSUFFICIENT_LOVELACES',
|
|
240
|
+
description:
|
|
241
|
+
'Order has insufficient lovelaces to cover execution fee and order output.',
|
|
141
242
|
};
|
|
142
243
|
}
|
|
143
244
|
|
|
@@ -148,7 +249,11 @@ export function summariseOrder(
|
|
|
148
249
|
rationalToFloat(order.datum.maxFeeRatio) <
|
|
149
250
|
rationalToFloat(psmPool.datum.mintingFeeRatio)
|
|
150
251
|
) {
|
|
151
|
-
return {
|
|
252
|
+
return {
|
|
253
|
+
_tag: 'ERROR',
|
|
254
|
+
errorTag: 'MAX_FEE',
|
|
255
|
+
description: 'Max fee ratio not satisfied',
|
|
256
|
+
};
|
|
152
257
|
}
|
|
153
258
|
|
|
154
259
|
// Mint order with one to one ratio case.
|
|
@@ -228,7 +333,11 @@ export function summariseOrder(
|
|
|
228
333
|
rationalToFloat(order.datum.maxFeeRatio) <
|
|
229
334
|
rationalToFloat(psmPool.datum.redemptionFeeRatio)
|
|
230
335
|
) {
|
|
231
|
-
return {
|
|
336
|
+
return {
|
|
337
|
+
_tag: 'ERROR',
|
|
338
|
+
errorTag: 'MAX_FEE',
|
|
339
|
+
description: 'Max fee ratio not satisfied',
|
|
340
|
+
};
|
|
232
341
|
}
|
|
233
342
|
|
|
234
343
|
const fee = calculateFeeFromRatio(
|
|
@@ -306,13 +415,15 @@ export function summariseOrder(
|
|
|
306
415
|
}
|
|
307
416
|
|
|
308
417
|
/**
|
|
309
|
-
* Pick only orders that are valid
|
|
418
|
+
* Pick only orders that are valid, belong to the PSM pool,
|
|
419
|
+
* and can be processed based on available liquidity.
|
|
310
420
|
*/
|
|
311
421
|
export function pickValidSatisfiableOrders(
|
|
422
|
+
lucid: LucidEvolution,
|
|
312
423
|
orders: ParsedOutput<StableswapOrderDatum>[],
|
|
313
424
|
pool: ParsedOutput<StableswapPoolContent>,
|
|
314
425
|
sysParams: SystemParams,
|
|
315
|
-
|
|
426
|
+
psmProcessingConfig?: PSMProcessingConfig,
|
|
316
427
|
): ParsedOutput<StableswapOrderDatum>[] {
|
|
317
428
|
const psmAvailableLiq = assetClassValueOf(
|
|
318
429
|
pool.utxo.assets,
|
|
@@ -321,7 +432,13 @@ export function pickValidSatisfiableOrders(
|
|
|
321
432
|
|
|
322
433
|
const validOrders = orders.flatMap((order) => {
|
|
323
434
|
try {
|
|
324
|
-
const res = summariseOrder(
|
|
435
|
+
const res = summariseOrder(
|
|
436
|
+
lucid,
|
|
437
|
+
order,
|
|
438
|
+
pool,
|
|
439
|
+
sysParams,
|
|
440
|
+
psmProcessingConfig,
|
|
441
|
+
);
|
|
325
442
|
return res._tag === 'SUCCESS' ? [res.result] : [];
|
|
326
443
|
} catch (_) {
|
|
327
444
|
return [];
|