@indigo-labs/indigo-sdk 0.1.19 → 0.1.21

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.
Files changed (135) hide show
  1. package/.github/workflows/ci.yml +8 -3
  2. package/dist/index.d.mts +1298 -677
  3. package/dist/index.d.ts +1298 -677
  4. package/dist/index.js +4650 -2217
  5. package/dist/index.mjs +4592 -2192
  6. package/eslint.config.mjs +7 -1
  7. package/package.json +9 -4
  8. package/src/contracts/cdp/helpers.ts +167 -0
  9. package/src/contracts/cdp/scripts.ts +33 -0
  10. package/src/contracts/cdp/transactions.ts +1310 -0
  11. package/src/contracts/cdp/types.ts +161 -0
  12. package/src/contracts/cdp-creator/scripts.ts +39 -0
  13. package/src/{types/indigo/cdp-creator.ts → contracts/cdp-creator/types.ts} +6 -4
  14. package/src/contracts/collector/scripts.ts +32 -0
  15. package/src/contracts/collector/transactions.ts +44 -0
  16. package/src/contracts/execute/scripts.ts +48 -0
  17. package/src/contracts/execute/types.ts +57 -0
  18. package/src/contracts/gov/helpers.ts +157 -0
  19. package/src/contracts/gov/scripts.ts +34 -0
  20. package/src/contracts/gov/transactions.ts +1224 -0
  21. package/src/contracts/gov/types-new.ts +115 -0
  22. package/src/contracts/gov/types.ts +89 -0
  23. package/src/{helpers/interest-oracle.ts → contracts/interest-oracle/helpers.ts} +37 -9
  24. package/src/contracts/interest-oracle/scripts.ts +18 -0
  25. package/src/contracts/interest-oracle/transactions.ts +149 -0
  26. package/src/{types/indigo/interest-oracle.ts → contracts/interest-oracle/types.ts} +1 -1
  27. package/src/contracts/lrp/scripts.ts +27 -0
  28. package/src/contracts/{lrp.ts → lrp/transactions.ts} +23 -23
  29. package/src/{types/indigo/lrp.ts → contracts/lrp/types.ts} +3 -3
  30. package/src/{scripts/one-shot-policy.ts → contracts/one-shot/scripts.ts} +1 -1
  31. package/src/contracts/{one-shot.ts → one-shot/transactions.ts} +3 -3
  32. package/src/contracts/poll/helpers.ts +55 -0
  33. package/src/contracts/poll/scripts.ts +72 -0
  34. package/src/contracts/poll/types-poll-manager.ts +38 -0
  35. package/src/contracts/poll/types-poll-shard.ts +38 -0
  36. package/src/contracts/poll/types-poll.ts +88 -0
  37. package/src/{scripts/price-oracle-validator.ts → contracts/price-oracle/scripts.ts} +1 -4
  38. package/src/contracts/price-oracle/transactions.ts +112 -0
  39. package/src/{types/indigo/price-oracle.ts → contracts/price-oracle/types.ts} +16 -4
  40. package/src/{helpers/stability-pool-helpers.ts → contracts/stability-pool/helpers.ts} +110 -6
  41. package/src/contracts/stability-pool/scripts.ts +46 -0
  42. package/src/contracts/stability-pool/transactions.ts +660 -0
  43. package/src/contracts/stability-pool/types-new.ts +208 -0
  44. package/src/contracts/stability-pool/types.ts +42 -0
  45. package/src/contracts/staking/helpers.ts +116 -0
  46. package/src/contracts/staking/scripts.ts +41 -0
  47. package/src/contracts/staking/transactions.ts +268 -0
  48. package/src/contracts/staking/types-new.ts +81 -0
  49. package/src/contracts/staking/types.ts +41 -0
  50. package/src/contracts/treasury/scripts.ts +37 -0
  51. package/src/contracts/treasury/transactions.ts +44 -0
  52. package/src/contracts/treasury/types.ts +55 -0
  53. package/src/contracts/version-registry/scripts.ts +29 -0
  54. package/src/contracts/version-registry/types-new.ts +19 -0
  55. package/src/{types/indigo/version-record.ts → contracts/version-registry/types.ts} +1 -1
  56. package/src/contracts/vesting/helpers.ts +267 -0
  57. package/src/index.ts +38 -33
  58. package/src/types/evolution-schema-options.ts +16 -0
  59. package/src/types/generic.ts +78 -60
  60. package/src/types/on-chain-decimal.ts +22 -0
  61. package/src/types/system-params.ts +22 -11
  62. package/src/utils/bigint-utils.ts +7 -0
  63. package/src/{helpers → utils}/helper-txs.ts +1 -0
  64. package/src/utils/time-helpers.ts +4 -0
  65. package/src/{helpers/helpers.ts → utils/utils.ts} +0 -10
  66. package/src/{helpers → utils}/value-helpers.ts +10 -0
  67. package/src/{scripts → validators}/cdp-creator-validator.ts +4 -50
  68. package/src/{scripts → validators}/cdp-validator.ts +3 -5
  69. package/src/{scripts → validators}/collector-validator.ts +2 -3
  70. package/src/{scripts/version-registry.ts → validators/execute-validator.ts} +3 -11
  71. package/src/{scripts/gov-validator.ts → validators/governance-validator.ts} +3 -40
  72. package/src/{scripts → validators}/interest-oracle-validator.ts +4 -20
  73. package/src/validators/lrp-validator.ts +7 -0
  74. package/src/validators/poll-manager-validator.ts +7 -0
  75. package/src/{scripts → validators}/poll-shard-validator.ts +3 -43
  76. package/src/{scripts → validators}/stability-pool-validator.ts +4 -57
  77. package/src/{scripts → validators}/staking-validator.ts +2 -3
  78. package/src/{scripts → validators}/treasury-validator.ts +2 -3
  79. package/src/{scripts → validators}/version-record-policy.ts +4 -23
  80. package/src/validators/version-registry-validator.ts +7 -0
  81. package/tests/cdp.test.ts +1565 -0
  82. package/tests/datums.test.ts +125 -108
  83. package/tests/endpoints/initialize.ts +240 -338
  84. package/tests/gov.test.ts +1874 -0
  85. package/tests/hash-checks.test.ts +26 -21
  86. package/tests/indigo-test-helpers.ts +1 -55
  87. package/tests/initialize.test.ts +10 -5
  88. package/tests/interest-calculations.test.ts +18 -18
  89. package/tests/interest-oracle.test.ts +20 -18
  90. package/tests/lrp.test.ts +180 -78
  91. package/tests/mock/assets-mock.ts +59 -0
  92. package/tests/queries/cdp-queries.ts +144 -0
  93. package/tests/queries/collector-queries.ts +26 -0
  94. package/tests/queries/execute-queries.ts +46 -0
  95. package/tests/queries/governance-queries.ts +19 -16
  96. package/tests/queries/iasset-queries.ts +46 -23
  97. package/tests/queries/interest-oracle-queries.ts +3 -6
  98. package/tests/queries/lrp-queries.ts +2 -2
  99. package/tests/queries/poll-queries.ts +97 -0
  100. package/tests/queries/price-oracle-queries.ts +5 -22
  101. package/tests/queries/stability-pool-queries.ts +10 -8
  102. package/tests/queries/staking-queries.ts +28 -19
  103. package/tests/queries/treasury-queries.ts +19 -0
  104. package/tests/stability-pool.test.ts +186 -71
  105. package/tests/staking.test.ts +30 -23
  106. package/tests/test-helpers.ts +11 -2
  107. package/tests/utils/asserts.ts +13 -0
  108. package/tests/utils/index.ts +50 -0
  109. package/tsconfig.json +3 -1
  110. package/vitest.config.ts +1 -1
  111. package/.github/workflows/test.yml +0 -44
  112. package/src/contracts/cdp.ts +0 -748
  113. package/src/contracts/collector.ts +0 -98
  114. package/src/contracts/gov.ts +0 -1
  115. package/src/contracts/interest-oracle.ts +0 -149
  116. package/src/contracts/stability-pool.ts +0 -692
  117. package/src/contracts/staking.ts +0 -348
  118. package/src/contracts/treasury.ts +0 -112
  119. package/src/helpers/asset-helpers.ts +0 -57
  120. package/src/helpers/staking-helpers.ts +0 -94
  121. package/src/helpers/time-helpers.ts +0 -4
  122. package/src/scripts/execute-validator.ts +0 -52
  123. package/src/scripts/lrp-validator.ts +0 -40
  124. package/src/scripts/poll-manager-validator.ts +0 -52
  125. package/src/types/indigo/cdp.ts +0 -88
  126. package/src/types/indigo/execute.ts +0 -21
  127. package/src/types/indigo/gov.ts +0 -51
  128. package/src/types/indigo/poll-manager.ts +0 -21
  129. package/src/types/indigo/poll-shard.ts +0 -16
  130. package/src/types/indigo/stability-pool.ts +0 -233
  131. package/src/types/indigo/staking.ts +0 -99
  132. /package/src/{types/one-shot.ts → contracts/one-shot/types.ts} +0 -0
  133. /package/src/{helpers/price-oracle-helpers.ts → contracts/price-oracle/helpers.ts} +0 -0
  134. /package/src/{helpers → utils}/indigo-helpers.ts +0 -0
  135. /package/src/{helpers → utils}/lucid-utils.ts +0 -0
@@ -0,0 +1,1565 @@
1
+ import {
2
+ addAssets,
3
+ Emulator,
4
+ EmulatorAccount,
5
+ fromText,
6
+ generateEmulatorAccount,
7
+ Lucid,
8
+ paymentCredentialOf,
9
+ stakeCredentialOf,
10
+ UTxO,
11
+ } from '@lucid-evolution/lucid';
12
+ import { assert, beforeEach, describe, expect, test } from 'vitest';
13
+ import { LucidContext, repeat, runAndAwaitTx } from './test-helpers';
14
+ import {
15
+ assetClassValueOf,
16
+ lovelacesAmt,
17
+ mkLovelacesOf,
18
+ } from '../src/utils/value-helpers';
19
+ import { AssetInfo, init } from './endpoints/initialize';
20
+ import {
21
+ addrDetails,
22
+ burnCdp,
23
+ CDPContent,
24
+ closeCdp,
25
+ createScriptAddress,
26
+ createSpAccount,
27
+ depositCdp,
28
+ freezeCdp,
29
+ fromSystemParamsAsset,
30
+ getInlineDatumOrThrow,
31
+ IAssetOutput,
32
+ InterestOracleDatum,
33
+ liquidateCdp,
34
+ matchSingle,
35
+ mergeCdps,
36
+ mintCdp,
37
+ openCdp,
38
+ parseInterestOracleDatum,
39
+ parsePriceOracleDatum,
40
+ processSpRequest,
41
+ redeemCdp,
42
+ SystemParams,
43
+ withdrawCdp,
44
+ } from '../src';
45
+ import {
46
+ findAllActiveCdps,
47
+ findCdp,
48
+ findFrozenCDPs,
49
+ findRandomCdpCreator,
50
+ } from './queries/cdp-queries';
51
+ import { findIAsset } from './queries/iasset-queries';
52
+ import { findPriceOracle } from './queries/price-oracle-queries';
53
+ import { match, P } from 'ts-pattern';
54
+ import { findRandomCollector } from './queries/collector-queries';
55
+ import { findGov } from './queries/governance-queries';
56
+ import { findRandomTreasuryUtxo } from './queries/treasury-queries';
57
+ import { getValueChangeAtAddressAfterAction } from './utils';
58
+ import { cdpCollateralRatioPercentage } from '../src/contracts/cdp/helpers';
59
+ import { OnChainDecimal } from '../src/types/on-chain-decimal';
60
+ import { findInterestOracle } from './queries/interest-oracle-queries';
61
+ import { feedPriceOracleTx } from '../src/contracts/price-oracle/transactions';
62
+ import { iusdInitialAssetCfg } from './mock/assets-mock';
63
+ import { assertValueInRange } from './utils/asserts';
64
+ import {
65
+ findStabilityPool,
66
+ findStabilityPoolAccount,
67
+ } from './queries/stability-pool-queries';
68
+
69
+ type MyContext = LucidContext<{
70
+ admin: EmulatorAccount;
71
+ user: EmulatorAccount;
72
+ }>;
73
+
74
+ async function findAllNecessaryOrefs(
75
+ context: MyContext,
76
+ sysParams: SystemParams,
77
+ asset: string,
78
+ ): Promise<{
79
+ stabilityPoolUtxo: UTxO;
80
+ iasset: IAssetOutput;
81
+ cdpCreatorUtxo: UTxO;
82
+ priceOracleUtxo: UTxO;
83
+ interestOracleUtxo: UTxO;
84
+ collectorUtxo: UTxO;
85
+ govUtxo: UTxO;
86
+ treasuryUtxo: UTxO;
87
+ }> {
88
+ const iasset = await findIAsset(
89
+ context.lucid,
90
+ sysParams.validatorHashes.cdpHash,
91
+ fromSystemParamsAsset(sysParams.cdpParams.iAssetAuthToken),
92
+ asset,
93
+ );
94
+
95
+ const stabilityPool = await findStabilityPool(
96
+ context.lucid,
97
+ sysParams.validatorHashes.stabilityPoolHash,
98
+ fromSystemParamsAsset(sysParams.stabilityPoolParams.stabilityPoolToken),
99
+ asset,
100
+ );
101
+
102
+ return {
103
+ stabilityPoolUtxo: stabilityPool,
104
+ iasset,
105
+ cdpCreatorUtxo: await findRandomCdpCreator(
106
+ context.lucid,
107
+ sysParams.validatorHashes.cdpCreatorHash,
108
+ fromSystemParamsAsset(sysParams.cdpCreatorParams.cdpCreatorNft),
109
+ ),
110
+ priceOracleUtxo: await findPriceOracle(
111
+ context.lucid,
112
+ match(iasset.datum.price)
113
+ .with({ Oracle: { content: P.select() } }, (oracleNft) => oracleNft)
114
+ .otherwise(() => {
115
+ throw new Error('Expected active oracle');
116
+ }),
117
+ ),
118
+ interestOracleUtxo: await findInterestOracle(
119
+ context.lucid,
120
+ iasset.datum.interestOracleNft,
121
+ ),
122
+ collectorUtxo: await findRandomCollector(
123
+ context.lucid,
124
+ sysParams.validatorHashes.collectorHash,
125
+ ),
126
+ govUtxo: (
127
+ await findGov(
128
+ context.lucid,
129
+ sysParams.validatorHashes.govHash,
130
+ fromSystemParamsAsset(sysParams.govParams.govNFT),
131
+ )
132
+ ).utxo,
133
+ treasuryUtxo: await findRandomTreasuryUtxo(
134
+ context.lucid,
135
+ sysParams.validatorHashes.treasuryHash,
136
+ ),
137
+ };
138
+ }
139
+
140
+ async function findPrice(
141
+ context: MyContext,
142
+ sysParams: SystemParams,
143
+ asset: string,
144
+ ): Promise<OnChainDecimal> {
145
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
146
+
147
+ const priceOracleUtxo = matchSingle(
148
+ await context.lucid.utxosByOutRef([orefs.priceOracleUtxo]),
149
+ (_) => new Error('Expected a single price oracle UTXO'),
150
+ );
151
+ const priceOracleDatum = parsePriceOracleDatum(
152
+ getInlineDatumOrThrow(priceOracleUtxo),
153
+ );
154
+
155
+ return priceOracleDatum.price;
156
+ }
157
+
158
+ async function findInterestDatum(
159
+ context: MyContext,
160
+ sysParams: SystemParams,
161
+ asset: string,
162
+ ): Promise<InterestOracleDatum> {
163
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
164
+
165
+ const interestOracleUtxo = matchSingle(
166
+ await context.lucid.utxosByOutRef([orefs.interestOracleUtxo]),
167
+ (_) => new Error('Expected a single interest oracle UTXO'),
168
+ );
169
+ return parseInterestOracleDatum(getInlineDatumOrThrow(interestOracleUtxo));
170
+ }
171
+
172
+ async function findCdpCR(
173
+ context: MyContext,
174
+ sysParams: SystemParams,
175
+ tokenAssetInfo: AssetInfo,
176
+ cdp: { utxo: UTxO; datum: CDPContent },
177
+ ): Promise<number> {
178
+ return cdpCollateralRatioPercentage(
179
+ context.emulator.slot,
180
+ await findPrice(context, sysParams, tokenAssetInfo.iassetTokenNameAscii),
181
+ cdp.utxo,
182
+ cdp.datum,
183
+ await findInterestDatum(
184
+ context,
185
+ sysParams,
186
+ tokenAssetInfo.iassetTokenNameAscii,
187
+ ),
188
+ context.lucid.config().network!,
189
+ );
190
+ }
191
+
192
+ describe('CDP', () => {
193
+ beforeEach<MyContext>(async (context: MyContext) => {
194
+ context.users = {
195
+ admin: generateEmulatorAccount({
196
+ lovelace: BigInt(100_000_000_000_000),
197
+ }),
198
+ user: generateEmulatorAccount(addAssets(mkLovelacesOf(150_000_000n))),
199
+ };
200
+
201
+ context.emulator = new Emulator([context.users.admin, context.users.user]);
202
+ context.lucid = await Lucid(context.emulator, 'Custom');
203
+ });
204
+
205
+ test<MyContext>('Open CDP', async (context: MyContext) => {
206
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
207
+
208
+ const [sysParams, _] = await init(context.lucid, [iusdInitialAssetCfg]);
209
+
210
+ const asset = 'iUSD';
211
+
212
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
213
+
214
+ await runAndAwaitTx(
215
+ context.lucid,
216
+ openCdp(
217
+ 10_000_000n,
218
+ 500_000n,
219
+ sysParams,
220
+ orefs.cdpCreatorUtxo,
221
+ orefs.iasset.utxo,
222
+ orefs.priceOracleUtxo,
223
+ orefs.interestOracleUtxo,
224
+ orefs.collectorUtxo,
225
+ context.lucid,
226
+ context.emulator.slot,
227
+ ),
228
+ );
229
+ });
230
+
231
+ test<MyContext>('Deposit CDP', async (context: MyContext) => {
232
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
233
+
234
+ const [pkh, skh] = await addrDetails(context.lucid);
235
+
236
+ const [sysParams, _] = await init(context.lucid, [iusdInitialAssetCfg]);
237
+
238
+ const asset = 'iUSD';
239
+
240
+ const initialMint = 500_000n;
241
+ const initialCollateral = 10_000_000n;
242
+
243
+ {
244
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
245
+
246
+ await runAndAwaitTx(
247
+ context.lucid,
248
+ openCdp(
249
+ initialCollateral,
250
+ initialMint,
251
+ sysParams,
252
+ orefs.cdpCreatorUtxo,
253
+ orefs.iasset.utxo,
254
+ orefs.priceOracleUtxo,
255
+ orefs.interestOracleUtxo,
256
+ orefs.collectorUtxo,
257
+ context.lucid,
258
+ context.emulator.slot,
259
+ ),
260
+ );
261
+ }
262
+
263
+ context.emulator.awaitSlot(1000);
264
+
265
+ {
266
+ const cdp = await findCdp(
267
+ context.lucid,
268
+ sysParams.validatorHashes.cdpHash,
269
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
270
+ pkh.hash,
271
+ skh,
272
+ );
273
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
274
+
275
+ const [_, treasuryValChange] = await getValueChangeAtAddressAfterAction(
276
+ context.lucid,
277
+ createScriptAddress(
278
+ context.lucid.config().network!,
279
+ sysParams.validatorHashes.treasuryHash,
280
+ ),
281
+ () =>
282
+ runAndAwaitTx(
283
+ context.lucid,
284
+ depositCdp(
285
+ 1_000_000n,
286
+ cdp.utxo,
287
+ orefs.iasset.utxo,
288
+ orefs.priceOracleUtxo,
289
+ orefs.interestOracleUtxo,
290
+ orefs.collectorUtxo,
291
+ orefs.govUtxo,
292
+ orefs.treasuryUtxo,
293
+ sysParams,
294
+ context.lucid,
295
+ context.emulator.slot,
296
+ ),
297
+ ),
298
+ );
299
+
300
+ assert(
301
+ lovelacesAmt(treasuryValChange) > 0,
302
+ 'Expected some interest paid to treasury',
303
+ );
304
+ }
305
+
306
+ const cdp = await findCdp(
307
+ context.lucid,
308
+ sysParams.validatorHashes.cdpHash,
309
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
310
+ pkh.hash,
311
+ skh,
312
+ );
313
+
314
+ expect(cdp.datum.mintedAmt).toBe(initialMint);
315
+ expect(lovelacesAmt(cdp.utxo.assets)).toBe(initialCollateral + 1_000_000n);
316
+ });
317
+
318
+ test<MyContext>('Withdraw CDP', async (context: MyContext) => {
319
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
320
+
321
+ const [pkh, skh] = await addrDetails(context.lucid);
322
+
323
+ const [sysParams, _] = await init(context.lucid, [iusdInitialAssetCfg]);
324
+
325
+ const asset = 'iUSD';
326
+
327
+ const initialMint = 500_000n;
328
+ const initialCollateral = 15_000_000n;
329
+
330
+ {
331
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
332
+
333
+ await runAndAwaitTx(
334
+ context.lucid,
335
+ openCdp(
336
+ initialCollateral,
337
+ initialMint,
338
+ sysParams,
339
+ orefs.cdpCreatorUtxo,
340
+ orefs.iasset.utxo,
341
+ orefs.priceOracleUtxo,
342
+ orefs.interestOracleUtxo,
343
+ orefs.collectorUtxo,
344
+ context.lucid,
345
+ context.emulator.slot,
346
+ ),
347
+ );
348
+ }
349
+
350
+ context.emulator.awaitSlot(100);
351
+
352
+ {
353
+ const cdp = await findCdp(
354
+ context.lucid,
355
+ sysParams.validatorHashes.cdpHash,
356
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
357
+ pkh.hash,
358
+ skh,
359
+ );
360
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
361
+
362
+ const [_, treasuryValChange] = await getValueChangeAtAddressAfterAction(
363
+ context.lucid,
364
+ createScriptAddress(
365
+ context.lucid.config().network!,
366
+ sysParams.validatorHashes.treasuryHash,
367
+ ),
368
+ () =>
369
+ runAndAwaitTx(
370
+ context.lucid,
371
+ withdrawCdp(
372
+ 4_000_000n,
373
+ cdp.utxo,
374
+ orefs.iasset.utxo,
375
+ orefs.priceOracleUtxo,
376
+ orefs.interestOracleUtxo,
377
+ orefs.collectorUtxo,
378
+ orefs.govUtxo,
379
+ orefs.treasuryUtxo,
380
+ sysParams,
381
+ context.lucid,
382
+ context.emulator.slot,
383
+ ),
384
+ ),
385
+ );
386
+
387
+ assert(
388
+ lovelacesAmt(treasuryValChange) > 0,
389
+ 'Expected some interest paid to treasury',
390
+ );
391
+ }
392
+
393
+ const cdp = await findCdp(
394
+ context.lucid,
395
+ sysParams.validatorHashes.cdpHash,
396
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
397
+ pkh.hash,
398
+ skh,
399
+ );
400
+
401
+ expect(cdp.datum.mintedAmt).toBe(initialMint);
402
+ expect(lovelacesAmt(cdp.utxo.assets)).toBe(initialCollateral - 4_000_000n);
403
+ });
404
+
405
+ test<MyContext>('Mint CDP', async (context: MyContext) => {
406
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
407
+
408
+ const [pkh, skh] = await addrDetails(context.lucid);
409
+
410
+ const [sysParams, _] = await init(context.lucid, [iusdInitialAssetCfg]);
411
+
412
+ const asset = 'iUSD';
413
+
414
+ const initialMint = 500_000n;
415
+ const initialCollateral = 12_000_000n;
416
+
417
+ {
418
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
419
+
420
+ await runAndAwaitTx(
421
+ context.lucid,
422
+ openCdp(
423
+ initialCollateral,
424
+ initialMint,
425
+ sysParams,
426
+ orefs.cdpCreatorUtxo,
427
+ orefs.iasset.utxo,
428
+ orefs.priceOracleUtxo,
429
+ orefs.interestOracleUtxo,
430
+ orefs.collectorUtxo,
431
+ context.lucid,
432
+ context.emulator.slot,
433
+ ),
434
+ );
435
+ }
436
+
437
+ context.emulator.awaitSlot(100);
438
+
439
+ {
440
+ const cdp = await findCdp(
441
+ context.lucid,
442
+ sysParams.validatorHashes.cdpHash,
443
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
444
+ pkh.hash,
445
+ skh,
446
+ );
447
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
448
+
449
+ const [_, treasuryValChange] = await getValueChangeAtAddressAfterAction(
450
+ context.lucid,
451
+ createScriptAddress(
452
+ context.lucid.config().network!,
453
+ sysParams.validatorHashes.treasuryHash,
454
+ ),
455
+ () =>
456
+ runAndAwaitTx(
457
+ context.lucid,
458
+ mintCdp(
459
+ 1_000n,
460
+ cdp.utxo,
461
+ orefs.iasset.utxo,
462
+ orefs.priceOracleUtxo,
463
+ orefs.interestOracleUtxo,
464
+ orefs.collectorUtxo,
465
+ orefs.govUtxo,
466
+ orefs.treasuryUtxo,
467
+ sysParams,
468
+ context.lucid,
469
+ context.emulator.slot,
470
+ ),
471
+ ),
472
+ );
473
+
474
+ assert(
475
+ lovelacesAmt(treasuryValChange) > 0,
476
+ 'Expected some interest paid to treasury',
477
+ );
478
+ }
479
+
480
+ const cdp = await findCdp(
481
+ context.lucid,
482
+ sysParams.validatorHashes.cdpHash,
483
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
484
+ pkh.hash,
485
+ skh,
486
+ );
487
+
488
+ expect(cdp.datum.mintedAmt).toBe(initialMint + 1_000n);
489
+ expect(lovelacesAmt(cdp.utxo.assets)).toBe(initialCollateral);
490
+ });
491
+
492
+ test<MyContext>('Burn CDP', async (context: MyContext) => {
493
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
494
+
495
+ const [pkh, skh] = await addrDetails(context.lucid);
496
+
497
+ const [sysParams, _] = await init(context.lucid, [iusdInitialAssetCfg]);
498
+
499
+ const asset = 'iUSD';
500
+
501
+ const initialMint = 500_000n;
502
+ const initialCollateral = 12_000_000n;
503
+
504
+ {
505
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
506
+
507
+ await runAndAwaitTx(
508
+ context.lucid,
509
+ openCdp(
510
+ initialCollateral,
511
+ initialMint,
512
+ sysParams,
513
+ orefs.cdpCreatorUtxo,
514
+ orefs.iasset.utxo,
515
+ orefs.priceOracleUtxo,
516
+ orefs.interestOracleUtxo,
517
+ orefs.collectorUtxo,
518
+ context.lucid,
519
+ context.emulator.slot,
520
+ ),
521
+ );
522
+ }
523
+
524
+ context.emulator.awaitSlot(1000);
525
+
526
+ {
527
+ const cdp = await findCdp(
528
+ context.lucid,
529
+ sysParams.validatorHashes.cdpHash,
530
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
531
+ pkh.hash,
532
+ skh,
533
+ );
534
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
535
+
536
+ const [_, treasuryValChange] = await getValueChangeAtAddressAfterAction(
537
+ context.lucid,
538
+ createScriptAddress(
539
+ context.lucid.config().network!,
540
+ sysParams.validatorHashes.treasuryHash,
541
+ ),
542
+ () =>
543
+ runAndAwaitTx(
544
+ context.lucid,
545
+ burnCdp(
546
+ 1_000n,
547
+ cdp.utxo,
548
+ orefs.iasset.utxo,
549
+ orefs.priceOracleUtxo,
550
+ orefs.interestOracleUtxo,
551
+ orefs.collectorUtxo,
552
+ orefs.govUtxo,
553
+ orefs.treasuryUtxo,
554
+ sysParams,
555
+ context.lucid,
556
+ context.emulator.slot,
557
+ ),
558
+ ),
559
+ );
560
+
561
+ assert(
562
+ lovelacesAmt(treasuryValChange) > 0,
563
+ 'Expected some interest paid to treasury',
564
+ );
565
+ }
566
+
567
+ const cdp = await findCdp(
568
+ context.lucid,
569
+ sysParams.validatorHashes.cdpHash,
570
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
571
+ pkh.hash,
572
+ skh,
573
+ );
574
+
575
+ expect(cdp.datum.mintedAmt).toBe(initialMint - 1_000n);
576
+ expect(lovelacesAmt(cdp.utxo.assets)).toBe(initialCollateral);
577
+ });
578
+
579
+ test<MyContext>('Close CDP', async (context: MyContext) => {
580
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
581
+
582
+ const [pkh, skh] = await addrDetails(context.lucid);
583
+
584
+ const [sysParams, _] = await init(context.lucid, [iusdInitialAssetCfg]);
585
+
586
+ const asset = 'iUSD';
587
+
588
+ {
589
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
590
+
591
+ await runAndAwaitTx(
592
+ context.lucid,
593
+ openCdp(
594
+ 10_000_000n,
595
+ 500_000n,
596
+ sysParams,
597
+ orefs.cdpCreatorUtxo,
598
+ orefs.iasset.utxo,
599
+ orefs.priceOracleUtxo,
600
+ orefs.interestOracleUtxo,
601
+ orefs.collectorUtxo,
602
+ context.lucid,
603
+ context.emulator.slot,
604
+ ),
605
+ );
606
+ }
607
+
608
+ context.emulator.awaitSlot(1000);
609
+
610
+ {
611
+ const cdp = await findCdp(
612
+ context.lucid,
613
+ sysParams.validatorHashes.cdpHash,
614
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
615
+ pkh.hash,
616
+ skh,
617
+ );
618
+
619
+ const orefs = await findAllNecessaryOrefs(context, sysParams, asset);
620
+
621
+ await runAndAwaitTx(
622
+ context.lucid,
623
+ closeCdp(
624
+ cdp.utxo,
625
+ orefs.iasset.utxo,
626
+ orefs.priceOracleUtxo,
627
+ orefs.interestOracleUtxo,
628
+ orefs.collectorUtxo,
629
+ orefs.govUtxo,
630
+ orefs.treasuryUtxo,
631
+ sysParams,
632
+ context.lucid,
633
+ context.emulator.slot,
634
+ ),
635
+ );
636
+ }
637
+ });
638
+
639
+ test<MyContext>('Redeem CDP', async (context: MyContext) => {
640
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
641
+
642
+ const [pkh, skh] = await addrDetails(context.lucid);
643
+
644
+ const [sysParams, [iusdAssetInfo]] = await init(context.lucid, [
645
+ iusdInitialAssetCfg,
646
+ ]);
647
+
648
+ {
649
+ const orefs = await findAllNecessaryOrefs(
650
+ context,
651
+ sysParams,
652
+ iusdAssetInfo.iassetTokenNameAscii,
653
+ );
654
+
655
+ await runAndAwaitTx(
656
+ context.lucid,
657
+ openCdp(
658
+ 20_000_000n,
659
+ 10_000_000n,
660
+ sysParams,
661
+ orefs.cdpCreatorUtxo,
662
+ orefs.iasset.utxo,
663
+ orefs.priceOracleUtxo,
664
+ orefs.interestOracleUtxo,
665
+ orefs.collectorUtxo,
666
+ context.lucid,
667
+ context.emulator.slot,
668
+ ),
669
+ );
670
+ }
671
+
672
+ // Add iAssets to user's wallet
673
+ {
674
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
675
+
676
+ const orefs = await findAllNecessaryOrefs(
677
+ context,
678
+ sysParams,
679
+ iusdAssetInfo.iassetTokenNameAscii,
680
+ );
681
+
682
+ await runAndAwaitTx(
683
+ context.lucid,
684
+ openCdp(
685
+ 50_000_000n,
686
+ 10_000_000n,
687
+ sysParams,
688
+ orefs.cdpCreatorUtxo,
689
+ orefs.iasset.utxo,
690
+ orefs.priceOracleUtxo,
691
+ orefs.interestOracleUtxo,
692
+ orefs.collectorUtxo,
693
+ context.lucid,
694
+ context.emulator.slot,
695
+ ),
696
+ );
697
+
698
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
699
+ }
700
+
701
+ {
702
+ const cdp = await findCdp(
703
+ context.lucid,
704
+ sysParams.validatorHashes.cdpHash,
705
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
706
+ pkh.hash,
707
+ skh,
708
+ );
709
+
710
+ assertValueInRange(
711
+ await findCdpCR(context, sysParams, iusdAssetInfo, cdp),
712
+ { min: 199, max: 200 },
713
+ );
714
+
715
+ const orefs = await findAllNecessaryOrefs(
716
+ context,
717
+ sysParams,
718
+ iusdAssetInfo.iassetTokenNameAscii,
719
+ );
720
+
721
+ await runAndAwaitTx(
722
+ context.lucid,
723
+ feedPriceOracleTx(
724
+ context.lucid,
725
+ orefs.priceOracleUtxo,
726
+ {
727
+ getOnChainInt: 1_250_000n,
728
+ },
729
+ iusdAssetInfo.oracleParams,
730
+ context.emulator.slot,
731
+ ),
732
+ );
733
+
734
+ assertValueInRange(
735
+ await findCdpCR(context, sysParams, iusdAssetInfo, cdp),
736
+ { min: 159, max: 160 },
737
+ );
738
+ }
739
+
740
+ {
741
+ // Let user do the redemption (i.e. not the CDP's owner)
742
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
743
+
744
+ const cdp = await findCdp(
745
+ context.lucid,
746
+ sysParams.validatorHashes.cdpHash,
747
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
748
+ pkh.hash,
749
+ skh,
750
+ );
751
+
752
+ const orefs = await findAllNecessaryOrefs(
753
+ context,
754
+ sysParams,
755
+ iusdAssetInfo.iassetTokenNameAscii,
756
+ );
757
+
758
+ await runAndAwaitTx(
759
+ context.lucid,
760
+ redeemCdp(
761
+ cdp.datum.mintedAmt,
762
+ cdp.utxo,
763
+ orefs.iasset.utxo,
764
+ orefs.priceOracleUtxo,
765
+ orefs.interestOracleUtxo,
766
+ orefs.collectorUtxo,
767
+ orefs.treasuryUtxo,
768
+ sysParams,
769
+ context.lucid,
770
+ context.emulator.slot,
771
+ ),
772
+ );
773
+
774
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
775
+ }
776
+
777
+ {
778
+ const cdp = await findCdp(
779
+ context.lucid,
780
+ sysParams.validatorHashes.cdpHash,
781
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
782
+ pkh.hash,
783
+ skh,
784
+ );
785
+
786
+ assertValueInRange(
787
+ await findCdpCR(context, sysParams, iusdAssetInfo, cdp),
788
+ { min: 199, max: 201 },
789
+ );
790
+ }
791
+ });
792
+
793
+ test<MyContext>('Freeze CDP', async (context: MyContext) => {
794
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
795
+
796
+ const [pkh, skh] = await addrDetails(context.lucid);
797
+
798
+ const [sysParams, [iusdAssetInfo]] = await init(context.lucid, [
799
+ iusdInitialAssetCfg,
800
+ ]);
801
+
802
+ {
803
+ const orefs = await findAllNecessaryOrefs(
804
+ context,
805
+ sysParams,
806
+ iusdAssetInfo.iassetTokenNameAscii,
807
+ );
808
+
809
+ await runAndAwaitTx(
810
+ context.lucid,
811
+ openCdp(
812
+ 20_000_000n,
813
+ 10_000_000n,
814
+ sysParams,
815
+ orefs.cdpCreatorUtxo,
816
+ orefs.iasset.utxo,
817
+ orefs.priceOracleUtxo,
818
+ orefs.interestOracleUtxo,
819
+ orefs.collectorUtxo,
820
+ context.lucid,
821
+ context.emulator.slot,
822
+ ),
823
+ );
824
+ }
825
+
826
+ context.emulator.awaitSlot(1000);
827
+
828
+ {
829
+ const cdp = await findCdp(
830
+ context.lucid,
831
+ sysParams.validatorHashes.cdpHash,
832
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
833
+ pkh.hash,
834
+ skh,
835
+ );
836
+
837
+ const orefs = await findAllNecessaryOrefs(
838
+ context,
839
+ sysParams,
840
+ iusdAssetInfo.iassetTokenNameAscii,
841
+ );
842
+
843
+ await runAndAwaitTx(
844
+ context.lucid,
845
+ feedPriceOracleTx(
846
+ context.lucid,
847
+ orefs.priceOracleUtxo,
848
+ {
849
+ getOnChainInt: 1_800_000n,
850
+ },
851
+ iusdAssetInfo.oracleParams,
852
+ context.emulator.slot,
853
+ ),
854
+ );
855
+
856
+ assertValueInRange(
857
+ await findCdpCR(context, sysParams, iusdAssetInfo, cdp),
858
+ { min: 111, max: 112 },
859
+ );
860
+ }
861
+
862
+ {
863
+ const cdp = await findCdp(
864
+ context.lucid,
865
+ sysParams.validatorHashes.cdpHash,
866
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
867
+ pkh.hash,
868
+ skh,
869
+ );
870
+
871
+ const orefs = await findAllNecessaryOrefs(
872
+ context,
873
+ sysParams,
874
+ iusdAssetInfo.iassetTokenNameAscii,
875
+ );
876
+
877
+ await runAndAwaitTx(
878
+ context.lucid,
879
+ freezeCdp(
880
+ cdp.utxo,
881
+ orefs.iasset.utxo,
882
+ orefs.priceOracleUtxo,
883
+ orefs.interestOracleUtxo,
884
+ sysParams,
885
+ context.lucid,
886
+ context.emulator.slot,
887
+ ),
888
+ );
889
+ }
890
+
891
+ {
892
+ const frozenCdp = matchSingle(
893
+ await findFrozenCDPs(
894
+ context.lucid,
895
+ sysParams.validatorHashes.cdpHash,
896
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
897
+ iusdAssetInfo.iassetTokenNameAscii,
898
+ ),
899
+ (_) => new Error('Expected only single frozen CDP'),
900
+ );
901
+
902
+ expect(
903
+ frozenCdp.datum.mintedAmt === 10_000_000n &&
904
+ frozenCdp.datum.cdpOwner == null,
905
+ 'Expected frozen certain frozen CDP',
906
+ ).toBeTruthy();
907
+ }
908
+ });
909
+
910
+ test<MyContext>('Liquidate CDP', async (context: MyContext) => {
911
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
912
+
913
+ const [sysParams, [iusdAssetInfo]] = await init(context.lucid, [
914
+ iusdInitialAssetCfg,
915
+ ]);
916
+
917
+ {
918
+ const orefs = await findAllNecessaryOrefs(
919
+ context,
920
+ sysParams,
921
+ iusdAssetInfo.iassetTokenNameAscii,
922
+ );
923
+
924
+ // This is the position that will get liquidated.
925
+ await runAndAwaitTx(
926
+ context.lucid,
927
+ openCdp(
928
+ 10_000_000n,
929
+ 5_000_000n,
930
+ sysParams,
931
+ orefs.cdpCreatorUtxo,
932
+ orefs.iasset.utxo,
933
+ orefs.priceOracleUtxo,
934
+ orefs.interestOracleUtxo,
935
+ orefs.collectorUtxo,
936
+ context.lucid,
937
+ context.emulator.slot,
938
+ ),
939
+ );
940
+ }
941
+
942
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
943
+
944
+ {
945
+ const orefs = await findAllNecessaryOrefs(
946
+ context,
947
+ sysParams,
948
+ iusdAssetInfo.iassetTokenNameAscii,
949
+ );
950
+
951
+ await runAndAwaitTx(
952
+ context.lucid,
953
+ openCdp(
954
+ 20_000_000n,
955
+ 10_000_000n,
956
+ sysParams,
957
+ orefs.cdpCreatorUtxo,
958
+ orefs.iasset.utxo,
959
+ orefs.priceOracleUtxo,
960
+ orefs.interestOracleUtxo,
961
+ orefs.collectorUtxo,
962
+ context.lucid,
963
+ context.emulator.slot,
964
+ ),
965
+ );
966
+
967
+ await runAndAwaitTx(
968
+ context.lucid,
969
+ createSpAccount(
970
+ iusdAssetInfo.iassetTokenNameAscii,
971
+ 10_000_000n,
972
+ sysParams,
973
+ context.lucid,
974
+ ),
975
+ );
976
+ }
977
+
978
+ // Process the create account request
979
+ {
980
+ const orefs = await findAllNecessaryOrefs(
981
+ context,
982
+ sysParams,
983
+ iusdAssetInfo.iassetTokenNameAscii,
984
+ );
985
+
986
+ const accountUtxo = await findStabilityPoolAccount(
987
+ context.lucid,
988
+ sysParams.validatorHashes.stabilityPoolHash,
989
+ paymentCredentialOf(context.users.user.address).hash,
990
+ iusdAssetInfo.iassetTokenNameAscii,
991
+ );
992
+
993
+ await runAndAwaitTx(
994
+ context.lucid,
995
+ processSpRequest(
996
+ iusdAssetInfo.iassetTokenNameAscii,
997
+ orefs.stabilityPoolUtxo,
998
+ accountUtxo,
999
+ orefs.govUtxo,
1000
+ orefs.iasset.utxo,
1001
+ undefined,
1002
+ sysParams,
1003
+ context.lucid,
1004
+ orefs.collectorUtxo,
1005
+ ),
1006
+ );
1007
+ }
1008
+
1009
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1010
+
1011
+ {
1012
+ const cdp = await findCdp(
1013
+ context.lucid,
1014
+ sysParams.validatorHashes.cdpHash,
1015
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1016
+ paymentCredentialOf(context.users.admin.address).hash,
1017
+ stakeCredentialOf(context.users.admin.address),
1018
+ );
1019
+
1020
+ const orefs = await findAllNecessaryOrefs(
1021
+ context,
1022
+ sysParams,
1023
+ iusdAssetInfo.iassetTokenNameAscii,
1024
+ );
1025
+
1026
+ await runAndAwaitTx(
1027
+ context.lucid,
1028
+ feedPriceOracleTx(
1029
+ context.lucid,
1030
+ orefs.priceOracleUtxo,
1031
+ {
1032
+ getOnChainInt: 1_800_000n,
1033
+ },
1034
+ iusdAssetInfo.oracleParams,
1035
+ context.emulator.slot,
1036
+ ),
1037
+ );
1038
+
1039
+ assertValueInRange(
1040
+ await findCdpCR(context, sysParams, iusdAssetInfo, cdp),
1041
+ { min: 111, max: 112 },
1042
+ );
1043
+ }
1044
+
1045
+ // We want user to do the freeze of admin's CDP
1046
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1047
+
1048
+ {
1049
+ const cdp = await findCdp(
1050
+ context.lucid,
1051
+ sysParams.validatorHashes.cdpHash,
1052
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1053
+ paymentCredentialOf(context.users.admin.address).hash,
1054
+ stakeCredentialOf(context.users.admin.address),
1055
+ );
1056
+
1057
+ const orefs = await findAllNecessaryOrefs(
1058
+ context,
1059
+ sysParams,
1060
+ iusdAssetInfo.iassetTokenNameAscii,
1061
+ );
1062
+
1063
+ await runAndAwaitTx(
1064
+ context.lucid,
1065
+ freezeCdp(
1066
+ cdp.utxo,
1067
+ orefs.iasset.utxo,
1068
+ orefs.priceOracleUtxo,
1069
+ orefs.interestOracleUtxo,
1070
+ sysParams,
1071
+ context.lucid,
1072
+ context.emulator.slot,
1073
+ ),
1074
+ );
1075
+ }
1076
+
1077
+ {
1078
+ const frozenCdp = matchSingle(
1079
+ await findFrozenCDPs(
1080
+ context.lucid,
1081
+ sysParams.validatorHashes.cdpHash,
1082
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1083
+ iusdAssetInfo.iassetTokenNameAscii,
1084
+ ),
1085
+ (_) => new Error('Expected only single frozen CDP'),
1086
+ );
1087
+
1088
+ const orefs = await findAllNecessaryOrefs(
1089
+ context,
1090
+ sysParams,
1091
+ iusdAssetInfo.iassetTokenNameAscii,
1092
+ );
1093
+
1094
+ await runAndAwaitTx(
1095
+ context.lucid,
1096
+ liquidateCdp(
1097
+ frozenCdp.utxo,
1098
+ orefs.stabilityPoolUtxo,
1099
+ orefs.collectorUtxo,
1100
+ orefs.treasuryUtxo,
1101
+ sysParams,
1102
+ context.lucid,
1103
+ ),
1104
+ );
1105
+ }
1106
+
1107
+ {
1108
+ const orefs = await findAllNecessaryOrefs(
1109
+ context,
1110
+ sysParams,
1111
+ iusdAssetInfo.iassetTokenNameAscii,
1112
+ );
1113
+
1114
+ expect(
1115
+ assetClassValueOf(orefs.stabilityPoolUtxo.assets, {
1116
+ currencySymbol: sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
1117
+ tokenName: fromText(iusdAssetInfo.iassetTokenNameAscii),
1118
+ }) === 5_000_000n,
1119
+ 'Expected different stability pool iassets amount',
1120
+ ).toBeTruthy();
1121
+ }
1122
+ });
1123
+
1124
+ test<MyContext>('Partialy liquidate CDP', async (context: MyContext) => {
1125
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1126
+
1127
+ const [sysParams, [iusdAssetInfo]] = await init(context.lucid, [
1128
+ iusdInitialAssetCfg,
1129
+ ]);
1130
+
1131
+ {
1132
+ const orefs = await findAllNecessaryOrefs(
1133
+ context,
1134
+ sysParams,
1135
+ iusdAssetInfo.iassetTokenNameAscii,
1136
+ );
1137
+
1138
+ // This is the position that will get liquidated.
1139
+ await runAndAwaitTx(
1140
+ context.lucid,
1141
+ openCdp(
1142
+ 10_000_000n,
1143
+ 5_000_000n,
1144
+ sysParams,
1145
+ orefs.cdpCreatorUtxo,
1146
+ orefs.iasset.utxo,
1147
+ orefs.priceOracleUtxo,
1148
+ orefs.interestOracleUtxo,
1149
+ orefs.collectorUtxo,
1150
+ context.lucid,
1151
+ context.emulator.slot,
1152
+ ),
1153
+ );
1154
+ }
1155
+
1156
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1157
+
1158
+ {
1159
+ const orefs = await findAllNecessaryOrefs(
1160
+ context,
1161
+ sysParams,
1162
+ iusdAssetInfo.iassetTokenNameAscii,
1163
+ );
1164
+
1165
+ await runAndAwaitTx(
1166
+ context.lucid,
1167
+ openCdp(
1168
+ 20_000_000n,
1169
+ 3_000_000n,
1170
+ sysParams,
1171
+ orefs.cdpCreatorUtxo,
1172
+ orefs.iasset.utxo,
1173
+ orefs.priceOracleUtxo,
1174
+ orefs.interestOracleUtxo,
1175
+ orefs.collectorUtxo,
1176
+ context.lucid,
1177
+ context.emulator.slot,
1178
+ ),
1179
+ );
1180
+
1181
+ await runAndAwaitTx(
1182
+ context.lucid,
1183
+ createSpAccount(
1184
+ iusdAssetInfo.iassetTokenNameAscii,
1185
+ 3_000_000n,
1186
+ sysParams,
1187
+ context.lucid,
1188
+ ),
1189
+ );
1190
+ }
1191
+
1192
+ // Process the create account request
1193
+ {
1194
+ const orefs = await findAllNecessaryOrefs(
1195
+ context,
1196
+ sysParams,
1197
+ iusdAssetInfo.iassetTokenNameAscii,
1198
+ );
1199
+
1200
+ const accountUtxo = await findStabilityPoolAccount(
1201
+ context.lucid,
1202
+ sysParams.validatorHashes.stabilityPoolHash,
1203
+ paymentCredentialOf(context.users.user.address).hash,
1204
+ iusdAssetInfo.iassetTokenNameAscii,
1205
+ );
1206
+
1207
+ await runAndAwaitTx(
1208
+ context.lucid,
1209
+ processSpRequest(
1210
+ iusdAssetInfo.iassetTokenNameAscii,
1211
+ orefs.stabilityPoolUtxo,
1212
+ accountUtxo,
1213
+ orefs.govUtxo,
1214
+ orefs.iasset.utxo,
1215
+ undefined,
1216
+ sysParams,
1217
+ context.lucid,
1218
+ orefs.collectorUtxo,
1219
+ ),
1220
+ );
1221
+ }
1222
+
1223
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1224
+
1225
+ {
1226
+ const cdp = await findCdp(
1227
+ context.lucid,
1228
+ sysParams.validatorHashes.cdpHash,
1229
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1230
+ paymentCredentialOf(context.users.admin.address).hash,
1231
+ stakeCredentialOf(context.users.admin.address),
1232
+ );
1233
+
1234
+ const orefs = await findAllNecessaryOrefs(
1235
+ context,
1236
+ sysParams,
1237
+ iusdAssetInfo.iassetTokenNameAscii,
1238
+ );
1239
+
1240
+ await runAndAwaitTx(
1241
+ context.lucid,
1242
+ feedPriceOracleTx(
1243
+ context.lucid,
1244
+ orefs.priceOracleUtxo,
1245
+ {
1246
+ getOnChainInt: 1_800_000n,
1247
+ },
1248
+ iusdAssetInfo.oracleParams,
1249
+ context.emulator.slot,
1250
+ ),
1251
+ );
1252
+
1253
+ assertValueInRange(
1254
+ await findCdpCR(context, sysParams, iusdAssetInfo, cdp),
1255
+ { min: 111, max: 112 },
1256
+ );
1257
+ }
1258
+
1259
+ // We want user to do the freeze of admin's CDP
1260
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1261
+
1262
+ {
1263
+ const cdp = await findCdp(
1264
+ context.lucid,
1265
+ sysParams.validatorHashes.cdpHash,
1266
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1267
+ paymentCredentialOf(context.users.admin.address).hash,
1268
+ stakeCredentialOf(context.users.admin.address),
1269
+ );
1270
+
1271
+ const orefs = await findAllNecessaryOrefs(
1272
+ context,
1273
+ sysParams,
1274
+ iusdAssetInfo.iassetTokenNameAscii,
1275
+ );
1276
+
1277
+ await runAndAwaitTx(
1278
+ context.lucid,
1279
+ freezeCdp(
1280
+ cdp.utxo,
1281
+ orefs.iasset.utxo,
1282
+ orefs.priceOracleUtxo,
1283
+ orefs.interestOracleUtxo,
1284
+ sysParams,
1285
+ context.lucid,
1286
+ context.emulator.slot,
1287
+ ),
1288
+ );
1289
+ }
1290
+
1291
+ {
1292
+ const frozenCdp = matchSingle(
1293
+ await findFrozenCDPs(
1294
+ context.lucid,
1295
+ sysParams.validatorHashes.cdpHash,
1296
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1297
+ iusdAssetInfo.iassetTokenNameAscii,
1298
+ ),
1299
+ (_) => new Error('Expected only single frozen CDP'),
1300
+ );
1301
+
1302
+ const orefs = await findAllNecessaryOrefs(
1303
+ context,
1304
+ sysParams,
1305
+ iusdAssetInfo.iassetTokenNameAscii,
1306
+ );
1307
+
1308
+ await runAndAwaitTx(
1309
+ context.lucid,
1310
+ liquidateCdp(
1311
+ frozenCdp.utxo,
1312
+ orefs.stabilityPoolUtxo,
1313
+ orefs.collectorUtxo,
1314
+ orefs.treasuryUtxo,
1315
+ sysParams,
1316
+ context.lucid,
1317
+ ),
1318
+ );
1319
+ }
1320
+
1321
+ {
1322
+ const orefs = await findAllNecessaryOrefs(
1323
+ context,
1324
+ sysParams,
1325
+ iusdAssetInfo.iassetTokenNameAscii,
1326
+ );
1327
+
1328
+ expect(
1329
+ assetClassValueOf(orefs.stabilityPoolUtxo.assets, {
1330
+ currencySymbol: sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
1331
+ tokenName: fromText(iusdAssetInfo.iassetTokenNameAscii),
1332
+ }) === 0n,
1333
+ 'Expected different stability pool iassets amount',
1334
+ ).toBeTruthy();
1335
+ }
1336
+ });
1337
+
1338
+ test<MyContext>('Merge CDPs and liquidate merged', async (context: MyContext) => {
1339
+ context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
1340
+
1341
+ const [sysParams, [iusdAssetInfo]] = await init(context.lucid, [
1342
+ iusdInitialAssetCfg,
1343
+ ]);
1344
+
1345
+ await repeat(3, async () => {
1346
+ const orefs = await findAllNecessaryOrefs(
1347
+ context,
1348
+ sysParams,
1349
+ iusdAssetInfo.iassetTokenNameAscii,
1350
+ );
1351
+
1352
+ await runAndAwaitTx(
1353
+ context.lucid,
1354
+ openCdp(
1355
+ 12_000_000n,
1356
+ 6_000_000n,
1357
+ sysParams,
1358
+ orefs.cdpCreatorUtxo,
1359
+ orefs.iasset.utxo,
1360
+ orefs.priceOracleUtxo,
1361
+ orefs.interestOracleUtxo,
1362
+ orefs.collectorUtxo,
1363
+ context.lucid,
1364
+ context.emulator.slot,
1365
+ ),
1366
+ );
1367
+ });
1368
+
1369
+ {
1370
+ const orefs = await findAllNecessaryOrefs(
1371
+ context,
1372
+ sysParams,
1373
+ iusdAssetInfo.iassetTokenNameAscii,
1374
+ );
1375
+
1376
+ await runAndAwaitTx(
1377
+ context.lucid,
1378
+ feedPriceOracleTx(
1379
+ context.lucid,
1380
+ orefs.priceOracleUtxo,
1381
+ {
1382
+ getOnChainInt: 1_800_000n,
1383
+ },
1384
+ iusdAssetInfo.oracleParams,
1385
+ context.emulator.slot,
1386
+ ),
1387
+ );
1388
+ }
1389
+
1390
+ {
1391
+ const activeCdps = await findAllActiveCdps(
1392
+ context.lucid,
1393
+ sysParams,
1394
+ iusdAssetInfo.iassetTokenNameAscii,
1395
+ stakeCredentialOf(context.users.admin.address),
1396
+ );
1397
+
1398
+ expect(activeCdps.length === 3, 'Expected 3 cdps').toBeTruthy();
1399
+
1400
+ for (const cdp of activeCdps) {
1401
+ const orefs = await findAllNecessaryOrefs(
1402
+ context,
1403
+ sysParams,
1404
+ iusdAssetInfo.iassetTokenNameAscii,
1405
+ );
1406
+
1407
+ await runAndAwaitTx(
1408
+ context.lucid,
1409
+ freezeCdp(
1410
+ cdp.utxo,
1411
+ orefs.iasset.utxo,
1412
+ orefs.priceOracleUtxo,
1413
+ orefs.interestOracleUtxo,
1414
+ sysParams,
1415
+ context.lucid,
1416
+ context.emulator.slot,
1417
+ ),
1418
+ );
1419
+ }
1420
+ }
1421
+
1422
+ {
1423
+ const frozenCdps = await findFrozenCDPs(
1424
+ context.lucid,
1425
+ sysParams.validatorHashes.cdpHash,
1426
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1427
+ iusdAssetInfo.iassetTokenNameAscii,
1428
+ );
1429
+
1430
+ expect(frozenCdps.length === 3, 'Expected 3 frozen cdps').toBeTruthy();
1431
+
1432
+ await runAndAwaitTx(
1433
+ context.lucid,
1434
+ mergeCdps(
1435
+ frozenCdps.map((cdp) => cdp.utxo),
1436
+ sysParams,
1437
+ context.lucid,
1438
+ ),
1439
+ );
1440
+ }
1441
+
1442
+ ///////////////////////////
1443
+ // Liquidation
1444
+ ///////////////////////////
1445
+
1446
+ context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase);
1447
+
1448
+ {
1449
+ const orefs = await findAllNecessaryOrefs(
1450
+ context,
1451
+ sysParams,
1452
+ iusdAssetInfo.iassetTokenNameAscii,
1453
+ );
1454
+
1455
+ await runAndAwaitTx(
1456
+ context.lucid,
1457
+ openCdp(
1458
+ 100_000_000n,
1459
+ 20_000_000n,
1460
+ sysParams,
1461
+ orefs.cdpCreatorUtxo,
1462
+ orefs.iasset.utxo,
1463
+ orefs.priceOracleUtxo,
1464
+ orefs.interestOracleUtxo,
1465
+ orefs.collectorUtxo,
1466
+ context.lucid,
1467
+ context.emulator.slot,
1468
+ ),
1469
+ );
1470
+
1471
+ await runAndAwaitTx(
1472
+ context.lucid,
1473
+ createSpAccount(
1474
+ iusdAssetInfo.iassetTokenNameAscii,
1475
+ 20_000_000n,
1476
+ sysParams,
1477
+ context.lucid,
1478
+ ),
1479
+ );
1480
+ }
1481
+
1482
+ // Process the create account request
1483
+ {
1484
+ const orefs = await findAllNecessaryOrefs(
1485
+ context,
1486
+ sysParams,
1487
+ iusdAssetInfo.iassetTokenNameAscii,
1488
+ );
1489
+
1490
+ const accountUtxo = await findStabilityPoolAccount(
1491
+ context.lucid,
1492
+ sysParams.validatorHashes.stabilityPoolHash,
1493
+ paymentCredentialOf(context.users.user.address).hash,
1494
+ iusdAssetInfo.iassetTokenNameAscii,
1495
+ );
1496
+
1497
+ await runAndAwaitTx(
1498
+ context.lucid,
1499
+ processSpRequest(
1500
+ iusdAssetInfo.iassetTokenNameAscii,
1501
+ orefs.stabilityPoolUtxo,
1502
+ accountUtxo,
1503
+ orefs.govUtxo,
1504
+ orefs.iasset.utxo,
1505
+ undefined,
1506
+ sysParams,
1507
+ context.lucid,
1508
+ orefs.collectorUtxo,
1509
+ ),
1510
+ );
1511
+ }
1512
+
1513
+ {
1514
+ const frozenCdp = matchSingle(
1515
+ await findFrozenCDPs(
1516
+ context.lucid,
1517
+ sysParams.validatorHashes.cdpHash,
1518
+ fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1519
+ iusdAssetInfo.iassetTokenNameAscii,
1520
+ ),
1521
+ (_) => new Error('Expected only single frozen CDP'),
1522
+ );
1523
+
1524
+ expect(
1525
+ frozenCdp.datum.mintedAmt === 18_000_000n &&
1526
+ frozenCdp.datum.cdpOwner == null,
1527
+ 'Expected frozen certain frozen CDP',
1528
+ ).toBeTruthy();
1529
+
1530
+ const orefs = await findAllNecessaryOrefs(
1531
+ context,
1532
+ sysParams,
1533
+ iusdAssetInfo.iassetTokenNameAscii,
1534
+ );
1535
+
1536
+ await runAndAwaitTx(
1537
+ context.lucid,
1538
+ liquidateCdp(
1539
+ frozenCdp.utxo,
1540
+ orefs.stabilityPoolUtxo,
1541
+ orefs.collectorUtxo,
1542
+ orefs.treasuryUtxo,
1543
+ sysParams,
1544
+ context.lucid,
1545
+ ),
1546
+ );
1547
+ }
1548
+
1549
+ {
1550
+ const orefs = await findAllNecessaryOrefs(
1551
+ context,
1552
+ sysParams,
1553
+ iusdAssetInfo.iassetTokenNameAscii,
1554
+ );
1555
+
1556
+ expect(
1557
+ assetClassValueOf(orefs.stabilityPoolUtxo.assets, {
1558
+ currencySymbol: sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
1559
+ tokenName: fromText(iusdAssetInfo.iassetTokenNameAscii),
1560
+ }) === 2_000_000n,
1561
+ 'Expected different stability pool iassets amount',
1562
+ ).toBeTruthy();
1563
+ }
1564
+ });
1565
+ });