@indigo-labs/indigo-sdk 0.4.3 → 0.5.0
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/.claude/settings.local.json +7 -0
- package/dist/index.d.mts +992 -905
- package/dist/index.d.ts +992 -905
- package/dist/index.js +2346 -2155
- package/dist/index.mjs +1925 -1750
- package/package.json +13 -21
- package/scripts/bench.sh +0 -0
- package/src/contracts/cdp/helpers.ts +7 -6
- package/src/contracts/cdp/transactions.ts +8 -29
- package/src/contracts/gov/transactions.ts +15 -17
- package/src/contracts/iasset/helpers.ts +2 -7
- package/src/contracts/initialize/actions.ts +0 -2
- package/src/contracts/initialize/helpers.ts +0 -4
- package/src/contracts/interest-collection/transactions.ts +2 -5
- package/src/contracts/interest-oracle/helpers.ts +4 -0
- package/src/contracts/interest-oracle/transactions.ts +1 -4
- package/src/contracts/price-oracle/helpers.ts +5 -11
- package/src/contracts/price-oracle/transactions.ts +2 -7
- package/src/contracts/rob/transactions.ts +0 -2
- package/src/contracts/rob-leverage/transactions.ts +1 -4
- package/{tests/queries/stability-pool-queries.ts → src/contracts/stability-pool/queries.ts} +22 -14
- package/src/contracts/stability-pool/transactions.ts +2 -8
- package/src/contracts/stableswap/helpers.ts +369 -1
- package/src/contracts/stableswap/transactions.ts +43 -191
- package/src/contracts/staking/transactions.ts +2 -7
- package/src/index.ts +4 -3
- package/tests/cdp/actions.ts +0 -11
- package/tests/cdp/cdp-helpers.ts +2 -2
- package/tests/cdp/cdp-queries.ts +8 -5
- package/tests/cdp/cdp.test.ts +409 -620
- package/tests/cdp/transactions-mutated.ts +30 -25
- package/tests/endpoints/initialize.ts +0 -2
- package/tests/gov/actions.ts +7 -32
- package/tests/gov/gov.test.ts +169 -401
- package/tests/indigo-test-helpers.ts +0 -1
- package/tests/initialize.test.ts +15 -20
- package/tests/interest-collection/interest-collection.test.ts +0 -4
- package/tests/interest-oracle.test.ts +1 -8
- package/tests/price-oracle/actions.ts +6 -8
- package/tests/price-oracle/price-oracle.test.ts +1 -13
- package/tests/price-oracle/transactions-mutated.ts +1 -4
- package/tests/pyth/pyth-feeds.test.ts +943 -0
- package/tests/pyth/pyth-indigo.test.ts +8 -12
- package/tests/pyth/pyth.test.ts +1 -2
- package/tests/rob/actions.ts +0 -2
- package/tests/rob/rob-leverage.test.ts +164 -220
- package/tests/rob/rob.test.ts +158 -263
- package/tests/rob/transactions-mutated.ts +7 -18
- package/tests/stability-pool/actions.ts +31 -22
- package/tests/stability-pool.test.ts +226 -319
- package/tests/stableswap/stableswap-actions.ts +0 -1
- package/tests/stableswap/stableswap.test.ts +226 -4
- package/tests/staking.test.ts +2 -13
- package/tests/treasury/treasury.test.ts +6 -30
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LucidEvolution, toHex, UTxO } from '@lucid-evolution/lucid';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
assetClassToUnit,
|
|
4
4
|
matchSingle,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from '../../
|
|
5
|
+
} from '@3rd-eye-labs/cardano-offchain-common';
|
|
6
|
+
import { option as O, array as A, function as F } from 'fp-ts';
|
|
7
|
+
import { fromSystemParamsAsset, SystemParams } from '../../types/system-params';
|
|
8
8
|
import {
|
|
9
9
|
AccountContent,
|
|
10
10
|
parseAccountDatum,
|
|
@@ -12,14 +12,16 @@ import {
|
|
|
12
12
|
parseStabilityPoolDatum,
|
|
13
13
|
SnapshotEpochToScaleToSumContent,
|
|
14
14
|
StabilityPoolContent,
|
|
15
|
-
} from '
|
|
16
|
-
import {
|
|
17
|
-
import { option as O, array as A, function as F } from 'fp-ts';
|
|
15
|
+
} from './types-new';
|
|
16
|
+
import { mkStabilityPoolAddr } from './helpers';
|
|
18
17
|
|
|
19
18
|
export async function findStabilityPool(
|
|
20
19
|
lucid: LucidEvolution,
|
|
21
20
|
sysParams: SystemParams,
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* For conversion from hex use the `fromHex` function from lucid-evolution.
|
|
23
|
+
*/
|
|
24
|
+
iassetName: Uint8Array<ArrayBufferLike>,
|
|
23
25
|
): Promise<{ utxo: UTxO; datum: StabilityPoolContent }> {
|
|
24
26
|
// We need to consider both with staking credential and without.
|
|
25
27
|
const spUtxos = await lucid.utxosAtWithUnit(
|
|
@@ -36,7 +38,7 @@ export async function findStabilityPool(
|
|
|
36
38
|
O.fromNullable(utxo.datum),
|
|
37
39
|
O.flatMap(parseStabilityPoolDatum),
|
|
38
40
|
O.flatMap((datum) => {
|
|
39
|
-
if (toHex(datum.iasset) ==
|
|
41
|
+
if (toHex(datum.iasset) == toHex(iassetName)) {
|
|
40
42
|
return O.some({ utxo, datum: datum });
|
|
41
43
|
} else {
|
|
42
44
|
return O.none;
|
|
@@ -57,7 +59,10 @@ export async function findStabilityPoolAccount(
|
|
|
57
59
|
lucid: LucidEvolution,
|
|
58
60
|
sysParams: SystemParams,
|
|
59
61
|
owner: string,
|
|
60
|
-
|
|
62
|
+
/**
|
|
63
|
+
* For conversion from hex use the `fromHex` function from lucid-evolution.
|
|
64
|
+
*/
|
|
65
|
+
iassetName: Uint8Array<ArrayBufferLike>,
|
|
61
66
|
): Promise<{ utxo: UTxO; datum: AccountContent }> {
|
|
62
67
|
// We need to consider both with staking credential and without.
|
|
63
68
|
const spUtxos = await lucid.utxosAt({
|
|
@@ -73,7 +78,7 @@ export async function findStabilityPoolAccount(
|
|
|
73
78
|
O.flatMap(parseAccountDatum),
|
|
74
79
|
O.flatMap((datum) => {
|
|
75
80
|
if (
|
|
76
|
-
toHex(datum.iasset) ==
|
|
81
|
+
toHex(datum.iasset) == toHex(iassetName) &&
|
|
77
82
|
toHex(datum.owner) == owner
|
|
78
83
|
) {
|
|
79
84
|
return O.some({ utxo, datum: datum });
|
|
@@ -93,7 +98,10 @@ export async function findStabilityPoolAccount(
|
|
|
93
98
|
export async function findE2s2sSnapshots(
|
|
94
99
|
lucid: LucidEvolution,
|
|
95
100
|
sysParams: SystemParams,
|
|
96
|
-
|
|
101
|
+
/**
|
|
102
|
+
* For conversion from hex use the `fromHex` function from lucid-evolution.
|
|
103
|
+
*/
|
|
104
|
+
iassetName: Uint8Array<ArrayBufferLike>,
|
|
97
105
|
): Promise<{ utxo: UTxO; datum: SnapshotEpochToScaleToSumContent }[]> {
|
|
98
106
|
// No need to query the ones without stake cred, e2s2s will always have stake cred based on script params.
|
|
99
107
|
const spUtxos = await lucid.utxosAtWithUnit(
|
|
@@ -111,7 +119,7 @@ export async function findE2s2sSnapshots(
|
|
|
111
119
|
O.fromNullable(utxo.datum),
|
|
112
120
|
O.flatMap(parseSnapshotEpochToScaleToSumDatum),
|
|
113
121
|
O.flatMap((datum) => {
|
|
114
|
-
if (toHex(datum.iasset) ==
|
|
122
|
+
if (toHex(datum.iasset) == toHex(iassetName)) {
|
|
115
123
|
return O.some({ utxo, datum: datum });
|
|
116
124
|
} else {
|
|
117
125
|
return O.none;
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
toHex,
|
|
9
9
|
addAssets,
|
|
10
10
|
OutRef,
|
|
11
|
-
slotToUnixTime,
|
|
12
11
|
credentialToAddress,
|
|
13
12
|
} from '@lucid-evolution/lucid';
|
|
14
13
|
import {
|
|
@@ -267,11 +266,9 @@ async function processSpRequestAuxiliary(
|
|
|
267
266
|
allE2s2sSnapshotOrefs: OutRef[],
|
|
268
267
|
sysParams: SystemParams,
|
|
269
268
|
lucid: LucidEvolution,
|
|
270
|
-
currentSlot: number,
|
|
271
269
|
txFee: bigint,
|
|
272
270
|
): Promise<TxBuilder> {
|
|
273
|
-
const
|
|
274
|
-
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
|
|
271
|
+
const currentTime = BigInt(lucid.slotToUnixTime(lucid.currentSlot()));
|
|
275
272
|
|
|
276
273
|
const stabilityPoolScriptRef = matchSingle(
|
|
277
274
|
await lucid.utxosByOutRef([
|
|
@@ -292,7 +289,7 @@ async function processSpRequestAuxiliary(
|
|
|
292
289
|
|
|
293
290
|
const baseRefInputs = [iAssetUtxo, stabilityPoolScriptRef];
|
|
294
291
|
|
|
295
|
-
const validFrom = slotToUnixTime(
|
|
292
|
+
const validFrom = lucid.slotToUnixTime(lucid.currentSlot() - 1);
|
|
296
293
|
const tx = lucid
|
|
297
294
|
.newTx()
|
|
298
295
|
.validFrom(validFrom)
|
|
@@ -770,7 +767,6 @@ export async function processSpRequest(
|
|
|
770
767
|
allE2s2sSnapshotOrefs: OutRef[],
|
|
771
768
|
sysParams: SystemParams,
|
|
772
769
|
lucid: LucidEvolution,
|
|
773
|
-
currentSlot: number,
|
|
774
770
|
): Promise<TxBuilder> {
|
|
775
771
|
const draftTx = processSpRequestAuxiliary(
|
|
776
772
|
stabilityPoolUtxo,
|
|
@@ -779,7 +775,6 @@ export async function processSpRequest(
|
|
|
779
775
|
allE2s2sSnapshotOrefs,
|
|
780
776
|
sysParams,
|
|
781
777
|
lucid,
|
|
782
|
-
currentSlot,
|
|
783
778
|
// Placeholder transation fee
|
|
784
779
|
1n,
|
|
785
780
|
);
|
|
@@ -793,7 +788,6 @@ export async function processSpRequest(
|
|
|
793
788
|
allE2s2sSnapshotOrefs,
|
|
794
789
|
sysParams,
|
|
795
790
|
lucid,
|
|
796
|
-
currentSlot,
|
|
797
791
|
fee,
|
|
798
792
|
);
|
|
799
793
|
}
|
|
@@ -1,9 +1,41 @@
|
|
|
1
1
|
import { fromHex, fromText, OutRef } from '@lucid-evolution/lucid';
|
|
2
|
-
import {
|
|
2
|
+
import { array as A, ord as Ord, function as F } from 'fp-ts';
|
|
3
|
+
import {
|
|
4
|
+
serialiseStableswapOutputDatum,
|
|
5
|
+
StableswapOrderDatum,
|
|
6
|
+
} from './types-new';
|
|
3
7
|
import { Data } from '@evolution-sdk/evolution';
|
|
8
|
+
import { ParsedOutput } from '../../types/generic';
|
|
9
|
+
import { assetClassValueOf } from '@3rd-eye-labs/cardano-offchain-common';
|
|
10
|
+
import { SystemParams } from '../../types/system-params';
|
|
11
|
+
import { StableswapPoolContent } from '../cdp/types-new';
|
|
12
|
+
import { calculateFeeFromRatio } from '../../utils/indigo-helpers';
|
|
13
|
+
import {
|
|
14
|
+
rationalDiv,
|
|
15
|
+
rationalFloor,
|
|
16
|
+
rationalFromInt,
|
|
17
|
+
rationalMul,
|
|
18
|
+
rationalToFloat,
|
|
19
|
+
} from '../../types/rational';
|
|
20
|
+
import { BigIntOrd } from '../../utils/bigint-utils';
|
|
4
21
|
|
|
5
22
|
export const BASE_MAX_EXECUTION_FEE = 1_620_000n;
|
|
6
23
|
|
|
24
|
+
export type OrderProcessConfig = {
|
|
25
|
+
/**
|
|
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).
|
|
28
|
+
*
|
|
29
|
+
* The default should be `false`. In case, owner wants to process
|
|
30
|
+
* such order himself, he can ignore the constraint.
|
|
31
|
+
*/
|
|
32
|
+
ignoreMaxExecutionFeeConstraint: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const defaultOrderProcessingConfig: OrderProcessConfig = {
|
|
36
|
+
ignoreMaxExecutionFeeConstraint: false,
|
|
37
|
+
};
|
|
38
|
+
|
|
7
39
|
export function createDestinationDatum(
|
|
8
40
|
datum: Data.Data | null,
|
|
9
41
|
outRef: OutRef,
|
|
@@ -20,3 +52,339 @@ export function createDestinationDatum(
|
|
|
20
52
|
|
|
21
53
|
return Data.toCBORHex(datum);
|
|
22
54
|
}
|
|
55
|
+
|
|
56
|
+
export type StableswapInfo = {
|
|
57
|
+
suppliedIasset: bigint;
|
|
58
|
+
suppliedCollateralAsset: bigint;
|
|
59
|
+
owedIasset: bigint;
|
|
60
|
+
owedCollateralAsset: bigint;
|
|
61
|
+
redemptionFee: bigint;
|
|
62
|
+
mintingFee: bigint;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type StableswapOrderInfo = {
|
|
66
|
+
order: ParsedOutput<StableswapOrderDatum>;
|
|
67
|
+
orderType: 'MINTING' | 'REDEEMING';
|
|
68
|
+
swapInfo: StableswapInfo;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Determine the PSM order type.
|
|
73
|
+
*/
|
|
74
|
+
export function psmOrderType(
|
|
75
|
+
order: ParsedOutput<StableswapOrderDatum>,
|
|
76
|
+
sysParams: SystemParams,
|
|
77
|
+
):
|
|
78
|
+
| { type: 'MINTING'; suppliedCollateral: bigint }
|
|
79
|
+
| { type: 'REDEEMING'; suppliedIassets: bigint }
|
|
80
|
+
| { type: 'ERROR'; reason: string } {
|
|
81
|
+
const iassetAc = {
|
|
82
|
+
currencySymbol: fromHex(
|
|
83
|
+
sysParams.stableswapParams.iassetSymbol.unCurrencySymbol,
|
|
84
|
+
),
|
|
85
|
+
tokenName: order.datum.iasset,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const suppliedIasset = assetClassValueOf(order.utxo.assets, iassetAc);
|
|
89
|
+
const suppliedCollateralAsset = assetClassValueOf(
|
|
90
|
+
order.utxo.assets,
|
|
91
|
+
order.datum.collateralAsset,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
(suppliedIasset != 0n && suppliedCollateralAsset != 0n) ||
|
|
96
|
+
(suppliedIasset == 0n && suppliedCollateralAsset == 0n)
|
|
97
|
+
) {
|
|
98
|
+
return {
|
|
99
|
+
type: 'ERROR',
|
|
100
|
+
reason: 'An order must supply either iAsset or collateral asset',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const isMinting = suppliedCollateralAsset > 0n;
|
|
105
|
+
|
|
106
|
+
return isMinting
|
|
107
|
+
? { type: 'MINTING', suppliedCollateral: suppliedCollateralAsset }
|
|
108
|
+
: { type: 'REDEEMING', suppliedIassets: suppliedIasset };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type SummaryResult =
|
|
112
|
+
| { _tag: 'SUCCESS'; result: StableswapOrderInfo }
|
|
113
|
+
| { _tag: 'ERROR'; reason: string };
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Summarise the order in detail
|
|
117
|
+
*/
|
|
118
|
+
export function summariseOrder(
|
|
119
|
+
order: ParsedOutput<StableswapOrderDatum>,
|
|
120
|
+
psmPool: ParsedOutput<StableswapPoolContent>,
|
|
121
|
+
sysParams: SystemParams,
|
|
122
|
+
orderProcessingConfig: OrderProcessConfig,
|
|
123
|
+
): SummaryResult {
|
|
124
|
+
const orderType = psmOrderType(order, sysParams);
|
|
125
|
+
|
|
126
|
+
if (orderType.type === 'ERROR') {
|
|
127
|
+
return { _tag: 'ERROR', reason: orderType.reason };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const isOneToOne =
|
|
131
|
+
psmPool.datum.collateralToIassetRatio.numerator ===
|
|
132
|
+
psmPool.datum.collateralToIassetRatio.denominator;
|
|
133
|
+
|
|
134
|
+
if (
|
|
135
|
+
!orderProcessingConfig.ignoreMaxExecutionFeeConstraint &&
|
|
136
|
+
order.datum.maxExecutionFee < BASE_MAX_EXECUTION_FEE
|
|
137
|
+
) {
|
|
138
|
+
return {
|
|
139
|
+
_tag: 'ERROR',
|
|
140
|
+
reason: `Max execution fee is too low. Minimum: ${BASE_MAX_EXECUTION_FEE}`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (orderType.type === 'MINTING') {
|
|
145
|
+
const suppliedCollateralAsset = orderType.suppliedCollateral;
|
|
146
|
+
|
|
147
|
+
if (
|
|
148
|
+
rationalToFloat(order.datum.maxFeeRatio) <
|
|
149
|
+
rationalToFloat(psmPool.datum.mintingFeeRatio)
|
|
150
|
+
) {
|
|
151
|
+
return { _tag: 'ERROR', reason: 'Max fee ratio not satisfied' };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Mint order with one to one ratio case.
|
|
155
|
+
if (isOneToOne) {
|
|
156
|
+
const fee = calculateFeeFromRatio(
|
|
157
|
+
psmPool.datum.mintingFeeRatio,
|
|
158
|
+
suppliedCollateralAsset,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
_tag: 'SUCCESS',
|
|
163
|
+
result: {
|
|
164
|
+
order: order,
|
|
165
|
+
orderType: 'MINTING',
|
|
166
|
+
swapInfo: {
|
|
167
|
+
suppliedCollateralAsset: suppliedCollateralAsset,
|
|
168
|
+
suppliedIasset: 0n,
|
|
169
|
+
owedCollateralAsset: 0n,
|
|
170
|
+
owedIasset: suppliedCollateralAsset - fee,
|
|
171
|
+
mintingFee: fee,
|
|
172
|
+
redemptionFee: 0n,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
// Mint order with any ratio case.
|
|
177
|
+
} else {
|
|
178
|
+
const iAssetConversion = rationalFloor(
|
|
179
|
+
rationalDiv(
|
|
180
|
+
rationalFromInt(suppliedCollateralAsset),
|
|
181
|
+
psmPool.datum.collateralToIassetRatio,
|
|
182
|
+
),
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const attemptedNormalizedCollateral = rationalFloor(
|
|
186
|
+
rationalMul(
|
|
187
|
+
rationalFromInt(iAssetConversion),
|
|
188
|
+
psmPool.datum.collateralToIassetRatio,
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const normalizedCollateralSupplied =
|
|
193
|
+
rationalFloor(
|
|
194
|
+
rationalDiv(
|
|
195
|
+
rationalFromInt(attemptedNormalizedCollateral),
|
|
196
|
+
psmPool.datum.collateralToIassetRatio,
|
|
197
|
+
),
|
|
198
|
+
) != iAssetConversion
|
|
199
|
+
? suppliedCollateralAsset
|
|
200
|
+
: attemptedNormalizedCollateral;
|
|
201
|
+
|
|
202
|
+
const fee = calculateFeeFromRatio(
|
|
203
|
+
psmPool.datum.mintingFeeRatio,
|
|
204
|
+
iAssetConversion,
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
_tag: 'SUCCESS',
|
|
209
|
+
result: {
|
|
210
|
+
order: order,
|
|
211
|
+
orderType: 'MINTING',
|
|
212
|
+
swapInfo: {
|
|
213
|
+
suppliedCollateralAsset: normalizedCollateralSupplied,
|
|
214
|
+
suppliedIasset: 0n,
|
|
215
|
+
owedIasset: iAssetConversion - fee,
|
|
216
|
+
owedCollateralAsset: 0n,
|
|
217
|
+
mintingFee: fee,
|
|
218
|
+
redemptionFee: 0n,
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// Redeem order case
|
|
224
|
+
} else {
|
|
225
|
+
const suppliedIasset = orderType.suppliedIassets;
|
|
226
|
+
|
|
227
|
+
if (
|
|
228
|
+
rationalToFloat(order.datum.maxFeeRatio) <
|
|
229
|
+
rationalToFloat(psmPool.datum.redemptionFeeRatio)
|
|
230
|
+
) {
|
|
231
|
+
return { _tag: 'ERROR', reason: 'Max fee ratio not satisfied' };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const fee = calculateFeeFromRatio(
|
|
235
|
+
psmPool.datum.redemptionFeeRatio,
|
|
236
|
+
suppliedIasset,
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const effectiveSuppliedIasset = suppliedIasset - fee;
|
|
240
|
+
|
|
241
|
+
// Redeem order with one to one ratio case
|
|
242
|
+
if (isOneToOne) {
|
|
243
|
+
return {
|
|
244
|
+
_tag: 'SUCCESS',
|
|
245
|
+
result: {
|
|
246
|
+
order: order,
|
|
247
|
+
orderType: 'REDEEMING',
|
|
248
|
+
swapInfo: {
|
|
249
|
+
suppliedIasset: effectiveSuppliedIasset,
|
|
250
|
+
suppliedCollateralAsset: 0n,
|
|
251
|
+
owedCollateralAsset: effectiveSuppliedIasset,
|
|
252
|
+
owedIasset: 0n,
|
|
253
|
+
redemptionFee: fee,
|
|
254
|
+
mintingFee: 0n,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
// Redeem order with any ratio case
|
|
259
|
+
} else {
|
|
260
|
+
const collateralConversion = rationalFloor(
|
|
261
|
+
rationalMul(
|
|
262
|
+
rationalFromInt(effectiveSuppliedIasset),
|
|
263
|
+
psmPool.datum.collateralToIassetRatio,
|
|
264
|
+
),
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const attemptedNormalizedEffectiveIasset = rationalFloor(
|
|
268
|
+
rationalDiv(
|
|
269
|
+
rationalFromInt(collateralConversion),
|
|
270
|
+
psmPool.datum.collateralToIassetRatio,
|
|
271
|
+
),
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
const normalizedEffectiveIasset =
|
|
275
|
+
rationalFloor(
|
|
276
|
+
rationalMul(
|
|
277
|
+
rationalFromInt(attemptedNormalizedEffectiveIasset),
|
|
278
|
+
psmPool.datum.collateralToIassetRatio,
|
|
279
|
+
),
|
|
280
|
+
) != collateralConversion
|
|
281
|
+
? effectiveSuppliedIasset
|
|
282
|
+
: attemptedNormalizedEffectiveIasset;
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
_tag: 'SUCCESS',
|
|
286
|
+
result: {
|
|
287
|
+
order: order,
|
|
288
|
+
orderType: 'REDEEMING',
|
|
289
|
+
swapInfo: {
|
|
290
|
+
suppliedIasset: normalizedEffectiveIasset,
|
|
291
|
+
suppliedCollateralAsset: 0n,
|
|
292
|
+
owedCollateralAsset: rationalFloor(
|
|
293
|
+
rationalMul(
|
|
294
|
+
rationalFromInt(effectiveSuppliedIasset),
|
|
295
|
+
psmPool.datum.collateralToIassetRatio,
|
|
296
|
+
),
|
|
297
|
+
),
|
|
298
|
+
owedIasset: 0n,
|
|
299
|
+
redemptionFee: fee,
|
|
300
|
+
mintingFee: 0n,
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Pick only orders that are valid and can be processed based on available liquidity.
|
|
310
|
+
*/
|
|
311
|
+
export function pickValidSatisfiableOrders(
|
|
312
|
+
orders: ParsedOutput<StableswapOrderDatum>[],
|
|
313
|
+
pool: ParsedOutput<StableswapPoolContent>,
|
|
314
|
+
sysParams: SystemParams,
|
|
315
|
+
orderProcessingConfig: OrderProcessConfig,
|
|
316
|
+
): ParsedOutput<StableswapOrderDatum>[] {
|
|
317
|
+
const psmAvailableLiq = assetClassValueOf(
|
|
318
|
+
pool.utxo.assets,
|
|
319
|
+
pool.datum.collateralAsset,
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
const validOrders = orders.flatMap((order) => {
|
|
323
|
+
try {
|
|
324
|
+
const res = summariseOrder(order, pool, sysParams, orderProcessingConfig);
|
|
325
|
+
return res._tag === 'SUCCESS' ? [res.result] : [];
|
|
326
|
+
} catch (_) {
|
|
327
|
+
return [];
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const { left: mintingOrders, right: redeemingOrdersSortedDesc } = F.pipe(
|
|
332
|
+
validOrders,
|
|
333
|
+
A.partition((o) => o.orderType === 'REDEEMING'),
|
|
334
|
+
({ left, right }) => ({
|
|
335
|
+
left,
|
|
336
|
+
// Sort the redeeming orders descending.
|
|
337
|
+
right: F.pipe(
|
|
338
|
+
right,
|
|
339
|
+
A.sort(
|
|
340
|
+
Ord.contramap(
|
|
341
|
+
(o: StableswapOrderInfo) => o.swapInfo.owedCollateralAsset,
|
|
342
|
+
)(Ord.reverse(BigIntOrd)),
|
|
343
|
+
),
|
|
344
|
+
),
|
|
345
|
+
}),
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
const totalCollateralDiff = F.pipe(
|
|
349
|
+
validOrders,
|
|
350
|
+
A.reduce<StableswapOrderInfo, bigint>(
|
|
351
|
+
0n,
|
|
352
|
+
(acc, order) =>
|
|
353
|
+
acc +
|
|
354
|
+
order.swapInfo.suppliedCollateralAsset -
|
|
355
|
+
order.swapInfo.owedCollateralAsset,
|
|
356
|
+
),
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
// When there's enough liquidity for processing all the orders,
|
|
360
|
+
// no need for addtional filtering.
|
|
361
|
+
if (psmAvailableLiq + totalCollateralDiff >= 0n) {
|
|
362
|
+
return validOrders.map((o) => o.order);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const collateralFromMinting = F.pipe(
|
|
366
|
+
mintingOrders,
|
|
367
|
+
A.reduce(0n, (acc, o) => acc + o.swapInfo.suppliedCollateralAsset),
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
// Take the redeeming orders from largest until there's enough liquidity.
|
|
371
|
+
const { selected } = F.pipe(
|
|
372
|
+
redeemingOrdersSortedDesc,
|
|
373
|
+
A.reduce(
|
|
374
|
+
{
|
|
375
|
+
intermediateCollateralAmt: psmAvailableLiq + collateralFromMinting,
|
|
376
|
+
selected: [] as StableswapOrderInfo[],
|
|
377
|
+
},
|
|
378
|
+
({ intermediateCollateralAmt, selected }, order) =>
|
|
379
|
+
intermediateCollateralAmt >= order.swapInfo.owedCollateralAsset
|
|
380
|
+
? {
|
|
381
|
+
intermediateCollateralAmt:
|
|
382
|
+
intermediateCollateralAmt - order.swapInfo.owedCollateralAsset,
|
|
383
|
+
selected: [...selected, order],
|
|
384
|
+
}
|
|
385
|
+
: { intermediateCollateralAmt, selected },
|
|
386
|
+
),
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
return [...mintingOrders, ...selected].map((o) => o.order);
|
|
390
|
+
}
|