@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/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 { fromHex as fromHex19, fromText as fromText14 } from "@lucid-evolution/lucid";
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 { assetClassValueOf as assetClassValueOf12 } from "@3rd-eye-labs/cardano-offchain-common";
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 defaultOrderProcessingConfig = {
11361
- ignoreMaxExecutionFeeConstraint: false
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, orderProcessingConfig) {
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 { _tag: "ERROR", reason: orderType.reason };
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 (!orderProcessingConfig.ignoreMaxExecutionFeeConstraint && order.datum.maxExecutionFee < BASE_MAX_EXECUTION_FEE) {
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
- reason: `Max execution fee is too low. Minimum: ${BASE_MAX_EXECUTION_FEE}`
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 { _tag: "ERROR", reason: "Max fee ratio not satisfied" };
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 { _tag: "ERROR", reason: "Max fee ratio not satisfied" };
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, orderProcessingConfig) {
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(order, pool, sysParams, orderProcessingConfig);
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 toHex19
11671
+ toHex as toHex20
11609
11672
  } from "@lucid-evolution/lucid";
11610
11673
  import {
11611
11674
  addressFromBech32 as addressFromBech323,
11612
- addressToBech32 as addressToBech323,
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 lovelacesAmt5,
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 expectedOutputLovelaces = estimateUtxoMinLovelace(
11645
- lucid.config().protocolParameters,
11646
- myAddress,
11707
+ const orderAssetsPlusFees = addAssets18(
11647
11708
  assetsToSwap,
11648
- {
11649
- kind: "inline",
11650
- value: createDestinationDatum(destinationInlineDatum ?? null, {
11651
- txHash: "0000000000000000000000000000000000000000000000000000000000000000",
11652
- outputIndex: 0
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(toHex19(stableswapOrderDatum.owner));
11748
+ ).addSignerKey(toHex20(stableswapOrderDatum.owner));
11694
11749
  }
11695
- async function batchProcessStableswapOrders(stableswapOrderOrefs, stableswapPoolOref, treasuryOref, sysParams, lucid, orderProcessingConfig = defaultOrderProcessingConfig) {
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
- orderProcessingConfig
11812
+ psmProcessingConfig
11760
11813
  );
11761
11814
  if (res._tag === "ERROR") {
11762
- throw new Error(res.reason);
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
- addressToBech323(
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
- lovelacesAmt5(orderInfo.order.utxo.assets) - orderInfo.order.datum.maxExecutionFee
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(toHex19(stableswapPoolDatum.feeManager)).setMinFee(1038402n);
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.0",
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.0",
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 { fromHex, fromText, OutRef } from '@lucid-evolution/lucid';
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 { assetClassValueOf } from '@3rd-eye-labs/cardano-offchain-common';
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 OrderProcessConfig = {
36
+ export type PSMProcessingConfig = {
25
37
  /**
26
- * Whether to ignore that an order has max execution fee set lower
27
- * than the threshold (i.e. the processor might be paying the remaining cardano tx fee).
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
- * The default should be `false`. In case, owner wants to process
30
- * such order himself, he can ignore the constraint.
41
+ * In case, owner wants to process such order himself, he can ignore the constraint.
42
+ * @default true
31
43
  */
32
- ignoreMaxExecutionFeeConstraint: boolean;
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
- export const defaultOrderProcessingConfig: OrderProcessConfig = {
36
- ignoreMaxExecutionFeeConstraint: false,
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'; reason: string };
173
+ | { _tag: 'ERROR'; errorTag: SummaryError; description: string };
114
174
 
115
175
  /**
116
- * Summarise the order in detail
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
- orderProcessingConfig: OrderProcessConfig,
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 { _tag: 'ERROR', reason: orderType.reason };
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
- !orderProcessingConfig.ignoreMaxExecutionFeeConstraint &&
221
+ config.enforceMaxExecutionFeeConstraint &&
136
222
  order.datum.maxExecutionFee < BASE_MAX_EXECUTION_FEE
137
223
  ) {
138
224
  return {
139
225
  _tag: 'ERROR',
140
- reason: `Max execution fee is too low. Minimum: ${BASE_MAX_EXECUTION_FEE}`,
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 { _tag: 'ERROR', reason: 'Max fee ratio not satisfied' };
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 { _tag: 'ERROR', reason: 'Max fee ratio not satisfied' };
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 and can be processed based on available liquidity.
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
- orderProcessingConfig: OrderProcessConfig,
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(order, pool, sysParams, orderProcessingConfig);
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 [];