@indigo-labs/indigo-sdk 0.1.2 → 0.1.3

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 (93) hide show
  1. package/.github/workflows/ci.yml +62 -0
  2. package/.github/workflows/test.yml +44 -0
  3. package/.husky/pre-commit +1 -0
  4. package/.prettierrc +1 -1
  5. package/README.md +52 -7
  6. package/dist/index.d.mts +1064 -182
  7. package/dist/index.d.ts +1064 -182
  8. package/dist/index.js +2565 -561
  9. package/dist/index.mjs +2546 -593
  10. package/eslint.config.mjs +35 -0
  11. package/package.json +61 -43
  12. package/src/contracts/cdp.ts +208 -359
  13. package/src/contracts/collector.ts +13 -6
  14. package/src/contracts/gov.ts +1 -58
  15. package/src/contracts/interest-oracle.ts +139 -39
  16. package/src/contracts/lrp.ts +223 -0
  17. package/src/contracts/one-shot.ts +67 -0
  18. package/src/contracts/stability-pool.ts +684 -0
  19. package/src/contracts/staking.ts +348 -0
  20. package/src/contracts/treasury.ts +30 -13
  21. package/src/helpers/asset-helpers.ts +51 -22
  22. package/src/helpers/helper-txs.ts +30 -0
  23. package/src/helpers/helpers.ts +29 -8
  24. package/src/helpers/indigo-helpers.ts +19 -0
  25. package/src/helpers/interest-oracle.ts +57 -0
  26. package/src/helpers/lucid-utils.ts +62 -16
  27. package/src/helpers/price-oracle-helpers.ts +36 -0
  28. package/src/helpers/stability-pool-helpers.ts +207 -0
  29. package/src/helpers/staking-helpers.ts +94 -0
  30. package/src/helpers/time-helpers.ts +4 -3
  31. package/src/helpers/value-helpers.ts +16 -0
  32. package/src/index.ts +15 -4
  33. package/src/scripts/always-fail-validator.ts +7 -0
  34. package/src/scripts/auth-token-policy.ts +23 -0
  35. package/src/scripts/cdp-creator-validator.ts +46 -2
  36. package/src/scripts/collector-validator.ts +2 -2
  37. package/src/scripts/execute-validator.ts +52 -0
  38. package/src/scripts/gov-validator.ts +44 -0
  39. package/src/scripts/iasset-policy.ts +22 -0
  40. package/src/scripts/interest-oracle-validator.ts +18 -3
  41. package/src/scripts/lrp-validator.ts +23 -0
  42. package/src/scripts/one-shot-policy.ts +62 -0
  43. package/src/scripts/poll-manager-validator.ts +52 -0
  44. package/src/scripts/poll-shard-validator.ts +47 -0
  45. package/src/scripts/price-oracle-validator.ts +26 -0
  46. package/src/scripts/stability-pool-validator.ts +60 -0
  47. package/src/scripts/staking-validator.ts +8 -0
  48. package/src/scripts/version-record-policy.ts +26 -0
  49. package/src/scripts/version-registry.ts +15 -0
  50. package/src/types/generic.ts +99 -6
  51. package/src/types/indigo/cdp-creator.ts +46 -0
  52. package/src/types/indigo/cdp.ts +86 -31
  53. package/src/types/indigo/execute.ts +21 -0
  54. package/src/types/indigo/gov.ts +50 -20
  55. package/src/types/indigo/interest-oracle.ts +55 -5
  56. package/src/types/indigo/lrp.ts +54 -0
  57. package/src/types/indigo/poll-manager.ts +21 -0
  58. package/src/types/indigo/poll-shard.ts +16 -0
  59. package/src/types/indigo/price-oracle.ts +38 -4
  60. package/src/types/indigo/stability-pool.ts +233 -0
  61. package/src/types/indigo/staking.ts +99 -0
  62. package/src/types/indigo/version-record.ts +17 -0
  63. package/src/types/on-chain-decimal.ts +23 -0
  64. package/src/types/one-shot.ts +22 -0
  65. package/src/types/system-params.ts +95 -77
  66. package/tests/data/system-params.json +972 -972
  67. package/tests/datums.test.ts +279 -44
  68. package/tests/endpoints/initialize.ts +1013 -0
  69. package/tests/hash-checks.test.ts +71 -15
  70. package/tests/indigo-test-helpers.ts +115 -0
  71. package/tests/initialize.test.ts +27 -0
  72. package/tests/interest-calculations.test.ts +110 -133
  73. package/tests/interest-oracle.test.ts +90 -0
  74. package/tests/lrp.test.ts +149 -0
  75. package/tests/queries/governance-queries.ts +31 -0
  76. package/tests/queries/iasset-queries.ts +39 -0
  77. package/tests/queries/interest-oracle-queries.ts +13 -0
  78. package/tests/queries/lrp-queries.ts +39 -0
  79. package/tests/queries/price-oracle-queries.ts +27 -0
  80. package/tests/queries/stability-pool-queries.ts +75 -0
  81. package/tests/queries/staking-queries.ts +43 -0
  82. package/tests/stability-pool.test.ts +364 -0
  83. package/tests/staking.test.ts +105 -0
  84. package/tests/test-helpers.ts +38 -0
  85. package/tsconfig.build.json +4 -0
  86. package/tsconfig.json +8 -27
  87. package/vitest.config.ts +9 -0
  88. package/babel.config.cjs +0 -13
  89. package/examples/sample-cdp.ts +0 -43
  90. package/jest.config.js +0 -13
  91. package/src/contracts/cdp-creator.ts +0 -86
  92. package/src/contracts/price-oracle.ts +0 -24
  93. package/src/helpers/cdp-helpers.ts +0 -9
@@ -3,12 +3,12 @@ import {
3
3
  Assets,
4
4
  Constr,
5
5
  Credential,
6
+ credentialToAddress,
6
7
  Data,
7
8
  fromText,
8
9
  LucidEvolution,
9
10
  OutRef,
10
11
  SpendingValidator,
11
- toText,
12
12
  TxBuilder,
13
13
  UTxO,
14
14
  validatorToAddress,
@@ -19,18 +19,28 @@ import {
19
19
  ScriptReferences,
20
20
  SystemParams,
21
21
  } from '../types/system-params';
22
- import { IAssetHelpers } from '../helpers/asset-helpers';
23
- import { PriceOracleContract } from './price-oracle';
24
- import { CDPCreatorContract } from './cdp-creator';
22
+ import { IAssetHelpers, IAssetOutput } from '../helpers/asset-helpers';
25
23
  import { CollectorContract } from './collector';
26
- import { InterestOracleContract } from './interest-oracle';
27
- import { GovContract } from './gov';
28
24
  import { TreasuryContract } from './treasury';
29
- import { addrDetails, getRandomElement, scriptRef } from '../helpers/lucid-utils';
30
- import { AssetClass } from '../types/generic';
31
- import { calculateFeeFromPercentage } from '../helpers/helpers';
32
- import { CDP, CDPDatum, CDPFees } from '../types/indigo/cdp';
25
+ import { addrDetails, scriptRef } from '../helpers/lucid-utils';
26
+ import {
27
+ calculateFeeFromPercentage,
28
+ getRandomElement,
29
+ } from '../helpers/helpers';
30
+ import {
31
+ CDPContent,
32
+ parseCDPDatum,
33
+ serialiseCDPDatum,
34
+ } from '../types/indigo/cdp';
33
35
  import { _cdpValidator } from '../scripts/cdp-validator';
36
+ import { parsePriceOracleDatum } from '../types/indigo/price-oracle';
37
+ import { parseInterestOracleDatum } from '../types/indigo/interest-oracle';
38
+ import { castCDPCreatorRedeemer } from '../types/indigo/cdp-creator';
39
+ import { parseGovDatum } from '../types/indigo/gov';
40
+ import {
41
+ calculateAccruedInterest,
42
+ calculateUnitaryInterestSinceOracleLastUpdated,
43
+ } from '../helpers/interest-oracle';
34
44
 
35
45
  export class CDPContract {
36
46
  static async openPosition(
@@ -44,58 +54,65 @@ export class CDPContract {
44
54
  interestOracleRef?: OutRef,
45
55
  cdpCreatorRef?: OutRef,
46
56
  collectorRef?: OutRef,
57
+ now: number = Date.now(),
47
58
  ): Promise<TxBuilder> {
48
59
  const [pkh, skh] = await addrDetails(lucid);
49
- const now = Date.now();
50
- const assetOut = await (assetRef
51
- ? IAssetHelpers.findIAssetByRef(assetRef, params, lucid)
60
+ const assetOut: IAssetOutput = await (assetRef
61
+ ? IAssetHelpers.findIAssetByRef(assetRef, lucid)
52
62
  : IAssetHelpers.findIAssetByName(asset, params, lucid));
53
-
63
+ if (!assetOut || !assetOut.datum) throw new Error('Unable to find IAsset');
54
64
  // Fail if delisted asset
55
- if ('getOnChainPrice' in assetOut.datum.price)
56
- return Promise.reject('Trying to open CDP against delisted asset');
65
+ if ('Delisted' in assetOut.datum.price)
66
+ return Promise.reject(
67
+ new Error('Trying to open CDP against delisted asset'),
68
+ );
57
69
 
58
- const oracleAsset = assetOut.datum.price as AssetClass;
70
+ const oracleAsset = assetOut.datum.price.Oracle.oracleNft.asset;
59
71
  const oracleOut = priceOracleRef
60
72
  ? (await lucid.utxosByOutRef([priceOracleRef]))[0]
61
73
  : await lucid.utxoByUnit(
62
- oracleAsset[0].unCurrencySymbol +
63
- fromText(oracleAsset[1].unTokenName),
74
+ oracleAsset.currencySymbol + oracleAsset.tokenName,
64
75
  );
65
- if (!oracleOut.datum) return Promise.reject('Price Oracle datum not found');
66
- const oracleDatum = PriceOracleContract.decodePriceOracleDatum(
67
- oracleOut.datum,
68
- );
76
+ if (!oracleOut.datum)
77
+ return Promise.reject(new Error('Price Oracle datum not found'));
78
+ const oracleDatum = parsePriceOracleDatum(oracleOut.datum);
69
79
 
70
- const interestOracleAsset = assetOut.datum.interestOracle;
80
+ const interestOracleAsset = assetOut.datum.interestOracleNft;
71
81
  const interestOracleOut = interestOracleRef
72
82
  ? (await lucid.utxosByOutRef([interestOracleRef]))[0]
73
83
  : await lucid.utxoByUnit(
74
- interestOracleAsset[0].unCurrencySymbol +
75
- fromText(interestOracleAsset[1].unTokenName),
84
+ interestOracleAsset.currencySymbol + interestOracleAsset.tokenName,
76
85
  );
77
86
  if (!interestOracleOut.datum)
78
- return Promise.reject('Interest Oracle datum not found');
79
- const interestOracleDatum =
80
- InterestOracleContract.decodeInterestOracleDatum(interestOracleOut.datum);
87
+ return Promise.reject(new Error('Interest Oracle datum not found'));
88
+ const interestOracleDatum = parseInterestOracleDatum(
89
+ interestOracleOut.datum,
90
+ );
81
91
 
82
92
  const cdpCreatorOut = getRandomElement(
83
93
  cdpCreatorRef
84
94
  ? await lucid.utxosByOutRef([cdpCreatorRef])
85
95
  : await lucid.utxosAtWithUnit(
86
- CDPCreatorContract.address(params.cdpCreatorParams, lucid),
96
+ credentialToAddress(lucid.config().network, {
97
+ type: 'Script',
98
+ hash: params.validatorHashes.cdpCreatorHash,
99
+ }),
87
100
  params.cdpCreatorParams.cdpCreatorNft[0].unCurrencySymbol +
88
101
  fromText(params.cdpCreatorParams.cdpCreatorNft[1].unTokenName),
89
102
  ),
90
103
  );
91
- const cdpCreatorRedeemer = CDPCreatorContract.redeemer(
92
- pkh,
93
- mintedAmount,
94
- collateralAmount,
95
- BigInt(now),
96
- );
97
- const cdpCreatorScriptRefUtxo = await CDPCreatorContract.scriptRef(
98
- params.scriptReferences,
104
+
105
+ const cdpCreatorRedeemer = castCDPCreatorRedeemer({
106
+ CreateCDP: {
107
+ cdpOwner: pkh.hash,
108
+ minted: mintedAmount,
109
+ collateral: collateralAmount,
110
+ currentTime: BigInt(now),
111
+ },
112
+ });
113
+
114
+ const cdpCreatorScriptRefUtxo = await scriptRef(
115
+ params.scriptReferences.cdpCreatorValidatorRef,
99
116
  lucid,
100
117
  );
101
118
 
@@ -108,16 +125,23 @@ export class CDPContract {
108
125
  lovelace: collateralAmount,
109
126
  };
110
127
  cdpValue[cdpToken] = 1n;
111
- const newSnapshot = InterestOracleContract.calculateUnitaryInterestSinceOracleLastUpdated(
112
- BigInt(now),
113
- interestOracleDatum,
114
- ) + interestOracleDatum.unitaryInterest;
115
- const cdpDatum = CDPContract.datum(pkh, asset, mintedAmount, {
116
- type: 'ActiveCDPInterestTracking',
117
- last_settled: BigInt(now),
118
- unitary_interest_snapshot: newSnapshot
119
- });
120
-
128
+ const newSnapshot =
129
+ calculateUnitaryInterestSinceOracleLastUpdated(
130
+ BigInt(now),
131
+ interestOracleDatum,
132
+ ) + interestOracleDatum.unitaryInterest;
133
+ const cdpDatum: CDPContent = {
134
+ cdpOwner: pkh.hash,
135
+ iasset: fromText(asset),
136
+ mintedAmt: mintedAmount,
137
+ cdpFees: {
138
+ ActiveCDPInterestTracking: {
139
+ lastSettled: BigInt(now),
140
+ unitaryInterestSnapshot: newSnapshot,
141
+ },
142
+ },
143
+ };
144
+
121
145
  const assetToken =
122
146
  params.cdpParams.cdpAssetSymbol.unCurrencySymbol + fromText(asset);
123
147
  const cdpTokenMintValue: Assets = {};
@@ -136,13 +160,13 @@ export class CDPContract {
136
160
 
137
161
  const debtMintingFee = calculateFeeFromPercentage(
138
162
  BigInt(assetOut.datum.debtMintingFeePercentage.getOnChainInt),
139
- (mintedAmount * oracleDatum.price) / 1_000_000n,
163
+ (mintedAmount * oracleDatum.price.getOnChainInt) / 1_000_000n,
140
164
  );
141
165
 
142
166
  // Oracle timestamp - 20s (length of a slot)
143
167
  const cappedValidateTo = oracleDatum.expiration - 20_001n;
144
168
  const timeValidFrom = now - 1_000;
145
- const timeValidTo_ = now + params.cdpCreatorParams.biasTime - 1_000;
169
+ const timeValidTo_ = now + Number(params.cdpCreatorParams.biasTime) - 1_000;
146
170
  const timeValidTo =
147
171
  cappedValidateTo <= timeValidFrom
148
172
  ? timeValidTo_
@@ -154,7 +178,7 @@ export class CDPContract {
154
178
  .readFrom([cdpCreatorScriptRefUtxo])
155
179
  .pay.ToContract(
156
180
  cdpAddress,
157
- { kind: 'inline', value: Data.to(cdpDatum) },
181
+ { kind: 'inline', value: serialiseCDPDatum(cdpDatum) },
158
182
  cdpValue,
159
183
  )
160
184
  .pay.ToContract(
@@ -168,18 +192,18 @@ export class CDPContract {
168
192
  .mintAssets(iassetTokenMintValue, Data.to(new Constr(0, [])))
169
193
  .readFrom([iAssetTokenScriptRefUtxo])
170
194
  .addSignerKey(pkh.hash)
171
- .validFrom(Number(now - 60_000))
195
+ .validFrom(Number(now - 100))
172
196
  .validTo(Number(timeValidTo));
173
197
 
174
- if (debtMintingFee > 0) {
175
- await CollectorContract.feeTx(
176
- debtMintingFee,
177
- lucid,
178
- params,
179
- tx,
180
- collectorRef,
181
- );
182
- }
198
+ if (debtMintingFee > 0) {
199
+ await CollectorContract.feeTx(
200
+ debtMintingFee,
201
+ lucid,
202
+ params,
203
+ tx,
204
+ collectorRef,
205
+ );
206
+ }
183
207
  return tx;
184
208
  }
185
209
 
@@ -305,23 +329,16 @@ export class CDPContract {
305
329
  treasuryRef?: OutRef,
306
330
  ): Promise<TxBuilder> {
307
331
  // Find Pkh, Skh
308
- const [pkh, skh] = await addrDetails(lucid);
332
+ const [pkh, _] = await addrDetails(lucid);
309
333
  const now = Date.now();
310
334
 
311
- // Fail if no pkh
312
- if (!pkh)
313
- return Promise.reject(
314
- 'Unable to determine the pub key hash of the wallet',
315
- );
316
-
317
335
  // Find Outputs: iAsset Output, CDP Output, Gov Output
318
336
  const cdp = (await lucid.utxosByOutRef([cdpRef]))[0];
319
- if (!cdp.datum) throw 'Unable to find CDP Datum';
320
- const cdpDatum = CDPContract.decodeCdpDatum(cdp.datum);
321
- if (cdpDatum.type !== 'CDP') throw 'Invalid CDP Datum';
337
+ if (!cdp.datum) throw new Error('Unable to find CDP Datum');
338
+ const cdpDatum = parseCDPDatum(cdp.datum);
322
339
  const iAsset = await (assetRef
323
- ? IAssetHelpers.findIAssetByRef(assetRef, params, lucid)
324
- : IAssetHelpers.findIAssetByName(cdpDatum.asset, params, lucid));
340
+ ? IAssetHelpers.findIAssetByRef(assetRef, lucid)
341
+ : IAssetHelpers.findIAssetByName(cdpDatum.iasset, params, lucid));
325
342
 
326
343
  const gov = govRef
327
344
  ? (await lucid.utxosByOutRef([govRef]))[0]
@@ -329,14 +346,8 @@ export class CDPContract {
329
346
  params.govParams.govNFT[0].unCurrencySymbol +
330
347
  fromText(params.govParams.govNFT[1].unTokenName),
331
348
  );
332
- // const [iAsset, cdp, gov] = await lucid.utxosByOutRef([
333
- // dIAssetTokenRef,
334
- // dCDPTokenRef,
335
- // dGovTokenRef,
336
- // ]);
337
- if (!gov.datum) throw 'Unable to find Gov Datum';
338
- const govData = GovContract.decodeGovDatum(gov.datum);
339
- if (!govData) throw 'No Governance datum found';
349
+ if (!gov.datum) throw new Error('Unable to find Gov Datum');
350
+ const govData = parseGovDatum(gov.datum);
340
351
  const cdpScriptRefUtxo = await CDPContract.scriptRef(
341
352
  params.scriptReferences,
342
353
  lucid,
@@ -344,87 +355,93 @@ export class CDPContract {
344
355
  const cdpAssets = Object.assign({}, cdp.assets);
345
356
  cdpAssets['lovelace'] = cdp.assets['lovelace'] + collateralAmount;
346
357
 
347
- const interestOracleAsset = iAsset.datum.interestOracle;
358
+ const interestOracleAsset = iAsset.datum.interestOracleNft;
348
359
  const interestOracleOut = interestOracleRef
349
360
  ? (await lucid.utxosByOutRef([interestOracleRef]))[0]
350
361
  : await lucid.utxoByUnit(
351
- interestOracleAsset[0].unCurrencySymbol +
352
- fromText(interestOracleAsset[1].unTokenName),
362
+ interestOracleAsset.currencySymbol +
363
+ fromText(interestOracleAsset.tokenName),
353
364
  );
354
365
  if (!interestOracleOut.datum)
355
- return Promise.reject('Interest Oracle datum not found');
356
- const interestOracleDatum =
357
- InterestOracleContract.decodeInterestOracleDatum(interestOracleOut.datum);
366
+ return Promise.reject(new Error('Interest Oracle datum not found'));
367
+ const interestOracleDatum = parseInterestOracleDatum(
368
+ interestOracleOut.datum,
369
+ );
358
370
 
359
- let tx = lucid
371
+ const tx = lucid
360
372
  .newTx()
361
- .collectFrom([cdp], Data.to(new Constr(0, [BigInt(now), mintAmount, collateralAmount])))
373
+ .collectFrom(
374
+ [cdp],
375
+ Data.to(new Constr(0, [BigInt(now), mintAmount, collateralAmount])),
376
+ )
362
377
  .readFrom([iAsset.utxo, gov, cdpScriptRefUtxo])
363
378
  .addSignerKey(pkh.hash);
364
- if (!cdp.datum) throw 'Unable to find CDP Datum';
365
- let cdpD = CDPContract.decodeCdpDatum(cdp.datum);
366
- if (!cdpD || cdpD.type !== 'CDP') throw 'Invalid CDP Datum';
367
-
368
- if (cdpD.fees.type !== 'ActiveCDPInterestTracking')
369
- throw 'Invalid CDP Fees';
370
-
371
- const newSnapshot = InterestOracleContract.calculateUnitaryInterestSinceOracleLastUpdated(
372
- BigInt(now),
373
- interestOracleDatum,
374
- ) + interestOracleDatum.unitaryInterest;
375
-
376
- const cdpD_: CDP = {
377
- ...cdpD,
378
- mintedAmount: cdpD.mintedAmount + mintAmount,
379
- fees: {
380
- type: 'ActiveCDPInterestTracking',
381
- last_settled: BigInt(now),
382
- unitary_interest_snapshot: newSnapshot
383
- }
379
+ if (!cdp.datum) throw new Error('Unable to find CDP Datum');
380
+ const cdpD = parseCDPDatum(cdp.datum);
381
+
382
+ if (!('ActiveCDPInterestTracking' in cdpD.cdpFees))
383
+ throw new Error('Invalid CDP Fees');
384
+
385
+ const newSnapshot =
386
+ calculateUnitaryInterestSinceOracleLastUpdated(
387
+ BigInt(now),
388
+ interestOracleDatum,
389
+ ) + interestOracleDatum.unitaryInterest;
390
+
391
+ const cdpD_: CDPContent = {
392
+ ...cdpD,
393
+ mintedAmt: cdpD.mintedAmt + mintAmount,
394
+ cdpFees: {
395
+ ActiveCDPInterestTracking: {
396
+ lastSettled: BigInt(now),
397
+ unitaryInterestSnapshot: newSnapshot,
398
+ },
399
+ },
384
400
  };
385
401
 
386
402
  tx.pay.ToContract(
387
403
  cdp.address,
388
404
  {
389
405
  kind: 'inline',
390
- value: CDPContract.encodeCdpDatum(cdpD_),
406
+ value: serialiseCDPDatum(cdpD_),
391
407
  },
392
408
  cdpAssets,
393
409
  );
394
410
 
395
411
  // Find Oracle Ref Input
396
- const oracleAsset = iAsset.datum.price as AssetClass;
412
+ const oracleAsset = iAsset.datum.price;
413
+ if (!('Oracle' in oracleAsset)) throw new Error('Invalid oracle asset');
397
414
  const oracleRefInput = priceOracleRef
398
415
  ? (await lucid.utxosByOutRef([priceOracleRef]))[0]
399
416
  : await lucid.utxoByUnit(
400
- oracleAsset[0].unCurrencySymbol +
401
- fromText(oracleAsset[1].unTokenName),
417
+ oracleAsset.Oracle.oracleNft.asset.currencySymbol +
418
+ fromText(oracleAsset.Oracle.oracleNft.asset.tokenName),
402
419
  );
403
420
 
404
421
  // Fail if delisted asset
405
- if (!oracleRefInput.datum) return Promise.reject('Invalid oracle input');
406
- const od = PriceOracleContract.decodePriceOracleDatum(oracleRefInput.datum);
407
- if (!od) return Promise.reject('Invalid oracle input');
422
+ if (!oracleRefInput.datum)
423
+ return Promise.reject(new Error('Invalid oracle input'));
424
+ const od = parsePriceOracleDatum(oracleRefInput.datum);
425
+ if (!od) return Promise.reject(new Error('Invalid oracle input'));
408
426
 
409
427
  // TODO: Sanity check: oacle expiration
410
428
  // Oracle timestamp - 20s (length of a slot)
411
429
  // Oracle timestamp - 20s (length of a slot)
412
430
  const cappedValidateTo = od.expiration - 20_001n;
413
431
  const timeValidFrom = now - 1_000;
414
- const timeValidTo_ = now + params.cdpCreatorParams.biasTime - 1_000;
432
+ const timeValidTo_ = now + Number(params.cdpCreatorParams.biasTime) - 1_000;
415
433
  const timeValidTo =
416
434
  cappedValidateTo <= timeValidFrom
417
435
  ? timeValidTo_
418
436
  : Math.min(timeValidTo_, Number(cappedValidateTo));
419
- tx
420
- .readFrom([oracleRefInput])
437
+ tx.readFrom([oracleRefInput])
421
438
  .validFrom(Number(timeValidFrom))
422
439
  .validTo(Number(timeValidTo));
423
440
 
424
441
  let fee = 0n;
425
442
  if (collateralAmount < 0) {
426
443
  fee += calculateFeeFromPercentage(
427
- govData.protocolParams.collateralFeePercentage,
444
+ govData.protocolParams.collateralFeePercentage.getOnChainInt,
428
445
  collateralAmount,
429
446
  );
430
447
  }
@@ -432,28 +449,35 @@ export class CDPContract {
432
449
  if (mintAmount > 0) {
433
450
  fee += calculateFeeFromPercentage(
434
451
  iAsset.datum.debtMintingFeePercentage.getOnChainInt,
435
- (mintAmount * od.price) / 1_000_000n,
452
+ (mintAmount * od.price.getOnChainInt) / 1_000_000n,
436
453
  );
437
454
  }
438
455
 
439
456
  // Interest payment
440
-
441
- const interestPaymentAsset = InterestOracleContract.calculateAccruedInterest(
457
+
458
+ const interestPaymentAsset = calculateAccruedInterest(
442
459
  BigInt(now),
443
- cdpD.fees.unitary_interest_snapshot,
444
- cdpD.mintedAmount,
445
- cdpD.fees.last_settled,
460
+ cdpD.cdpFees.ActiveCDPInterestTracking.unitaryInterestSnapshot,
461
+ cdpD.mintedAmt,
462
+ cdpD.cdpFees.ActiveCDPInterestTracking.lastSettled,
446
463
  interestOracleDatum,
447
464
  );
448
- const interestPayment = (interestPaymentAsset * od.price) / 1_000_000n;
465
+ const interestPayment =
466
+ (interestPaymentAsset * od.price.getOnChainInt) / 1_000_000n;
449
467
  const interestCollectorPayment = calculateFeeFromPercentage(
450
468
  iAsset.datum.interestCollectorPortionPercentage.getOnChainInt,
451
469
  interestPayment,
452
470
  );
453
471
  const interestTreasuryPayment = interestPayment - interestCollectorPayment;
454
- console.log(interestPayment, interestCollectorPayment, interestTreasuryPayment);
472
+
455
473
  if (interestTreasuryPayment > 0) {
456
- await TreasuryContract.feeTx(interestTreasuryPayment, lucid, params, tx, treasuryRef);
474
+ await TreasuryContract.feeTx(
475
+ interestTreasuryPayment,
476
+ lucid,
477
+ params,
478
+ tx,
479
+ treasuryRef,
480
+ );
457
481
  }
458
482
 
459
483
  fee += interestCollectorPayment;
@@ -465,7 +489,7 @@ export class CDPContract {
465
489
  lucid,
466
490
  );
467
491
  const iassetToken =
468
- params.cdpParams.cdpAssetSymbol.unCurrencySymbol + fromText(cdpD.asset);
492
+ params.cdpParams.cdpAssetSymbol.unCurrencySymbol + cdpD.iasset;
469
493
  const mintValue = {} as Assets;
470
494
  mintValue[iassetToken] = mintAmount;
471
495
 
@@ -476,7 +500,7 @@ export class CDPContract {
476
500
  }
477
501
 
478
502
  if (fee > 0n) {
479
- await CollectorContract.feeTx(fee, lucid, params, tx, collectorRef)
503
+ await CollectorContract.feeTx(fee, lucid, params, tx, collectorRef);
480
504
  }
481
505
 
482
506
  return tx;
@@ -494,23 +518,16 @@ export class CDPContract {
494
518
  treasuryRef?: OutRef,
495
519
  ): Promise<TxBuilder> {
496
520
  // Find Pkh, Skh
497
- const [pkh, skh] = await addrDetails(lucid);
521
+ const [pkh, _] = await addrDetails(lucid);
498
522
  const now = Date.now();
499
523
 
500
- // Fail if no pkh
501
- if (!pkh)
502
- return Promise.reject(
503
- 'Unable to determine the pub key hash of the wallet',
504
- );
505
-
506
524
  // Find Outputs: iAsset Output, CDP Output, Gov Output
507
525
  const cdp = (await lucid.utxosByOutRef([cdpRef]))[0];
508
- if (!cdp.datum) throw 'Unable to find CDP Datum';
509
- const cdpDatum = CDPContract.decodeCdpDatum(cdp.datum);
510
- if (cdpDatum.type !== 'CDP') throw 'Invalid CDP Datum';
526
+ if (!cdp.datum) throw new Error('Unable to find CDP Datum');
527
+ const cdpDatum = parseCDPDatum(cdp.datum);
511
528
  const iAsset = await (assetRef
512
- ? IAssetHelpers.findIAssetByRef(assetRef, params, lucid)
513
- : IAssetHelpers.findIAssetByName(cdpDatum.asset, params, lucid));
529
+ ? IAssetHelpers.findIAssetByRef(assetRef, lucid)
530
+ : IAssetHelpers.findIAssetByName(cdpDatum.iasset, params, lucid));
514
531
 
515
532
  const gov = govRef
516
533
  ? (await lucid.utxosByOutRef([govRef]))[0]
@@ -518,87 +535,91 @@ export class CDPContract {
518
535
  params.govParams.govNFT[0].unCurrencySymbol +
519
536
  fromText(params.govParams.govNFT[1].unTokenName),
520
537
  );
521
-
522
- if (!gov.datum) throw 'Unable to find Gov Datum';
523
- const govData = GovContract.decodeGovDatum(gov.datum);
524
- if (!govData) throw 'No Governance datum found';
538
+
539
+ if (!gov.datum) throw new Error('Unable to find Gov Datum');
525
540
  const cdpScriptRefUtxo = await CDPContract.scriptRef(
526
541
  params.scriptReferences,
527
542
  lucid,
528
543
  );
529
544
 
530
- const interestOracleAsset = iAsset.datum.interestOracle;
545
+ const interestOracleAsset = iAsset.datum.interestOracleNft;
531
546
  const interestOracleOut = interestOracleRef
532
547
  ? (await lucid.utxosByOutRef([interestOracleRef]))[0]
533
548
  : await lucid.utxoByUnit(
534
- interestOracleAsset[0].unCurrencySymbol +
535
- fromText(interestOracleAsset[1].unTokenName),
549
+ interestOracleAsset.currencySymbol +
550
+ fromText(interestOracleAsset.tokenName),
536
551
  );
537
552
  if (!interestOracleOut.datum)
538
- return Promise.reject('Interest Oracle datum not found');
539
- const interestOracleDatum =
540
- InterestOracleContract.decodeInterestOracleDatum(interestOracleOut.datum);
553
+ return Promise.reject(new Error('Interest Oracle datum not found'));
554
+ const interestOracleDatum = parseInterestOracleDatum(
555
+ interestOracleOut.datum,
556
+ );
541
557
 
542
- let tx = lucid
558
+ const tx = lucid
543
559
  .newTx()
544
560
  .collectFrom([cdp], Data.to(new Constr(1, [BigInt(now)])))
545
561
  .readFrom([iAsset.utxo, gov, cdpScriptRefUtxo])
546
562
  .addSignerKey(pkh.hash);
547
- if (!cdp.datum) throw 'Unable to find CDP Datum';
548
- let cdpD = CDPContract.decodeCdpDatum(cdp.datum);
549
- if (!cdpD || cdpD.type !== 'CDP') throw 'Invalid CDP Datum';
550
-
551
- if (cdpD.fees.type !== 'ActiveCDPInterestTracking')
552
- throw 'Invalid CDP Fees';
563
+ if (!cdp.datum) throw new Error('Unable to find CDP Datum');
564
+ const cdpD = parseCDPDatum(cdp.datum);
565
+ if (!('ActiveCDPInterestTracking' in cdpD.cdpFees))
566
+ throw new Error('Invalid CDP Fees');
553
567
 
554
568
  // Find Oracle Ref Input
555
- const oracleAsset = iAsset.datum.price as AssetClass;
569
+ if (!('Oracle' in iAsset.datum.price))
570
+ throw new Error('iAsset is delisted');
571
+ const oracleAsset = iAsset.datum.price.Oracle.oracleNft.asset;
556
572
  const oracleRefInput = priceOracleRef
557
573
  ? (await lucid.utxosByOutRef([priceOracleRef]))[0]
558
574
  : await lucid.utxoByUnit(
559
- oracleAsset[0].unCurrencySymbol +
560
- fromText(oracleAsset[1].unTokenName),
575
+ oracleAsset.currencySymbol + fromText(oracleAsset.tokenName),
561
576
  );
562
577
 
563
578
  // Fail if delisted asset
564
- if (!oracleRefInput.datum) return Promise.reject('Invalid oracle input');
565
- const od = PriceOracleContract.decodePriceOracleDatum(oracleRefInput.datum);
566
- if (!od) return Promise.reject('Invalid oracle input');
579
+ if (!oracleRefInput.datum)
580
+ return Promise.reject(new Error('Invalid oracle input'));
581
+ const od = parsePriceOracleDatum(oracleRefInput.datum);
567
582
 
568
583
  // TODO: Sanity check: oacle expiration
569
584
  // Oracle timestamp - 20s (length of a slot)
570
585
  // Oracle timestamp - 20s (length of a slot)
571
586
  const cappedValidateTo = od.expiration - 20_001n;
572
587
  const timeValidFrom = now - 1_000;
573
- const timeValidTo_ = now + params.cdpCreatorParams.biasTime - 1_000;
588
+ const timeValidTo_ = now + Number(params.cdpCreatorParams.biasTime) - 1_000;
574
589
  const timeValidTo =
575
590
  cappedValidateTo <= timeValidFrom
576
591
  ? timeValidTo_
577
592
  : Math.min(timeValidTo_, Number(cappedValidateTo));
578
- tx
579
- .readFrom([oracleRefInput])
593
+ tx.readFrom([oracleRefInput])
580
594
  .validFrom(Number(timeValidFrom))
581
595
  .validTo(Number(timeValidTo));
582
596
 
583
597
  let fee = 0n;
584
598
 
585
599
  // Interest payment
586
- const interestPaymentAsset = InterestOracleContract.calculateAccruedInterest(
600
+ const interestPaymentAsset = calculateAccruedInterest(
587
601
  BigInt(now),
588
- cdpD.fees.unitary_interest_snapshot,
589
- cdpD.mintedAmount,
590
- cdpD.fees.last_settled,
602
+ cdpD.cdpFees.ActiveCDPInterestTracking.unitaryInterestSnapshot,
603
+ cdpD.mintedAmt,
604
+ cdpD.cdpFees.ActiveCDPInterestTracking.lastSettled,
591
605
  interestOracleDatum,
592
606
  );
593
- const interestPayment = (interestPaymentAsset * od.price) / 1_000_000n;
607
+ const interestPayment =
608
+ (interestPaymentAsset * od.price.getOnChainInt) / 1_000_000n;
594
609
  const interestCollectorPayment = calculateFeeFromPercentage(
595
610
  iAsset.datum.interestCollectorPortionPercentage.getOnChainInt,
596
611
  interestPayment,
597
612
  );
598
613
  const interestTreasuryPayment = interestPayment - interestCollectorPayment;
599
- console.log(interestPayment, interestCollectorPayment, interestTreasuryPayment);
614
+
600
615
  if (interestTreasuryPayment > 0) {
601
- await TreasuryContract.feeTx(interestTreasuryPayment, lucid, params, tx, treasuryRef);
616
+ await TreasuryContract.feeTx(
617
+ interestTreasuryPayment,
618
+ lucid,
619
+ params,
620
+ tx,
621
+ treasuryRef,
622
+ );
602
623
  }
603
624
 
604
625
  fee += interestCollectorPayment;
@@ -609,202 +630,30 @@ export class CDPContract {
609
630
  lucid,
610
631
  );
611
632
  const iassetToken =
612
- params.cdpParams.cdpAssetSymbol.unCurrencySymbol + fromText(cdpD.asset);
633
+ params.cdpParams.cdpAssetSymbol.unCurrencySymbol + cdpD.iasset;
613
634
  const assetBurnValue = {} as Assets;
614
- assetBurnValue[iassetToken] = -BigInt(cdpD.mintedAmount);
635
+ assetBurnValue[iassetToken] = -BigInt(cdpD.mintedAmt);
615
636
  const cdpTokenBurnValue = {} as Assets;
616
- cdpTokenBurnValue[params.cdpParams.cdpAuthToken[0].unCurrencySymbol + fromText(params.cdpParams.cdpAuthToken[1].unTokenName)] = -1n;
637
+ cdpTokenBurnValue[
638
+ params.cdpParams.cdpAuthToken[0].unCurrencySymbol +
639
+ fromText(params.cdpParams.cdpAuthToken[1].unTokenName)
640
+ ] = -1n;
617
641
  const cdpAuthTokenScriptRefUtxo = await CDPContract.cdpAuthTokenRef(
618
642
  params.scriptReferences,
619
643
  lucid,
620
644
  );
621
- tx.readFrom([iAssetTokenScriptRefUtxo]).mintAssets(
622
- assetBurnValue,
623
- Data.to(new Constr(0, [])),
624
- ).readFrom([cdpAuthTokenScriptRefUtxo]).mintAssets(
625
- cdpTokenBurnValue,
626
- Data.to(new Constr(0, [])),
627
- );
645
+ tx.readFrom([iAssetTokenScriptRefUtxo])
646
+ .mintAssets(assetBurnValue, Data.to(new Constr(0, [])))
647
+ .readFrom([cdpAuthTokenScriptRefUtxo])
648
+ .mintAssets(cdpTokenBurnValue, Data.to(new Constr(0, [])));
628
649
 
629
650
  if (fee > 0n) {
630
- await CollectorContract.feeTx(fee, lucid, params, tx, collectorRef)
651
+ await CollectorContract.feeTx(fee, lucid, params, tx, collectorRef);
631
652
  }
632
653
 
633
654
  return tx;
634
655
  }
635
656
 
636
- static decodeCdpDatum(datum: string): CDPDatum {
637
- const cdpDatum = Data.from(datum) as any;
638
- if (cdpDatum.index == 1 && cdpDatum.fields[0].index == 0) {
639
- const iasset = cdpDatum.fields[0].fields;
640
- return {
641
- type: 'IAsset',
642
- name: toText(iasset[0]),
643
- price:
644
- iasset[1].index === 0
645
- ? { getOnChainInt: iasset[1].fields[0] }
646
- : [
647
- { unCurrencySymbol: iasset[1].fields[0].fields[0].fields[0] },
648
- {
649
- unTokenName: toText(iasset[1].fields[0].fields[0].fields[1]),
650
- },
651
- ],
652
- interestOracle: [
653
- { unCurrencySymbol: iasset[2].fields[0] },
654
- { unTokenName: toText(iasset[2].fields[1]) },
655
- ],
656
- redemptionRatioPercentage: { getOnChainInt: iasset[3].fields[0] },
657
- maintenanceRatioPercentage: { getOnChainInt: iasset[4].fields[0] },
658
- liquidationRatioPercentage: { getOnChainInt: iasset[5].fields[0] },
659
- debtMintingFeePercentage: { getOnChainInt: iasset[6].fields[0] },
660
- liquidationProcessingFeePercentage: {
661
- getOnChainInt: iasset[7].fields[0],
662
- },
663
- stabilityPoolWithdrawalFeePercentage: {
664
- getOnChainInt: iasset[8].fields[0],
665
- },
666
- redemptionReimbursementPercentage: {
667
- getOnChainInt: iasset[9].fields[0],
668
- },
669
- redemptionProcessingFeePercentage: {
670
- getOnChainInt: iasset[10].fields[0],
671
- },
672
- interestCollectorPortionPercentage: {
673
- getOnChainInt: iasset[11].fields[0],
674
- },
675
- firstAsset: iasset[12].index === 1,
676
- nextAsset:
677
- iasset[13].index === 0 ? toText(iasset[13].fields[0]) : undefined,
678
- };
679
- } else if (cdpDatum.index == 0 && cdpDatum.fields[0].index == 0) {
680
- const cdp = cdpDatum.fields[0].fields;
681
- return {
682
- type: 'CDP',
683
- owner: cdp[0].fields[0],
684
- asset: toText(cdp[1]),
685
- mintedAmount: cdp[2],
686
- fees:
687
- cdp[3].index === 0
688
- ? {
689
- type: 'ActiveCDPInterestTracking',
690
- last_settled: cdp[3].fields[0],
691
- unitary_interest_snapshot: cdp[3].fields[1],
692
- }
693
- : {
694
- type: 'FrozenCDPAccumulatedFees',
695
- lovelaces_treasury: cdp[3].fields[0],
696
- lovelaces_indy_stakers: cdp[3].fields[1],
697
- },
698
- };
699
- }
700
-
701
- throw 'Invalid CDP Datum provided';
702
- }
703
-
704
- static encodeCdpDatum(datum: CDPDatum): string {
705
- if (datum.type === 'CDP') {
706
- return Data.to(
707
- new Constr(0, [
708
- new Constr(0, [
709
- datum.owner ? new Constr(0, [datum.owner]) : new Constr(1, []),
710
- fromText(datum.asset),
711
- BigInt(datum.mintedAmount),
712
- datum.fees.type === 'ActiveCDPInterestTracking'
713
- ? new Constr(0, [
714
- datum.fees.last_settled,
715
- datum.fees.unitary_interest_snapshot,
716
- ])
717
- : new Constr(1, [
718
- datum.fees.lovelaces_treasury,
719
- datum.fees.lovelaces_indy_stakers,
720
- ]),
721
- ]),
722
- ]),
723
- );
724
- } else if (datum.type === 'IAsset') {
725
- return Data.to(
726
- new Constr(1, [
727
- new Constr(0, [
728
- fromText(datum.name),
729
- 'getOnChainInt' in datum.price
730
- ? new Constr(0, [
731
- new Constr(0, [BigInt(datum.price.getOnChainInt)]),
732
- ])
733
- : new Constr(1, [
734
- new Constr(0, [
735
- new Constr(0, [
736
- datum.price[0].unCurrencySymbol,
737
- fromText(datum.price[1].unTokenName),
738
- ]),
739
- ]),
740
- ]),
741
- new Constr(0, [
742
- datum.interestOracle[0].unCurrencySymbol,
743
- fromText(datum.interestOracle[1].unTokenName),
744
- ]),
745
- new Constr(0, [
746
- BigInt(datum.redemptionRatioPercentage.getOnChainInt),
747
- ]),
748
- new Constr(0, [
749
- BigInt(datum.maintenanceRatioPercentage.getOnChainInt),
750
- ]),
751
- new Constr(0, [
752
- BigInt(datum.liquidationRatioPercentage.getOnChainInt),
753
- ]),
754
- new Constr(0, [
755
- BigInt(datum.debtMintingFeePercentage.getOnChainInt),
756
- ]),
757
- new Constr(0, [
758
- BigInt(datum.liquidationProcessingFeePercentage.getOnChainInt),
759
- ]),
760
- new Constr(0, [
761
- BigInt(datum.stabilityPoolWithdrawalFeePercentage.getOnChainInt),
762
- ]),
763
- new Constr(0, [
764
- BigInt(datum.redemptionReimbursementPercentage.getOnChainInt),
765
- ]),
766
- new Constr(0, [
767
- BigInt(datum.redemptionProcessingFeePercentage.getOnChainInt),
768
- ]),
769
- new Constr(0, [
770
- BigInt(datum.interestCollectorPortionPercentage.getOnChainInt),
771
- ]),
772
- datum.firstAsset ? new Constr(1, []) : new Constr(0, []),
773
- datum.nextAsset
774
- ? new Constr(0, [fromText(datum.nextAsset)])
775
- : new Constr(1, []),
776
- ]),
777
- ]),
778
- );
779
- }
780
-
781
- throw 'Invalid CDP Datum provided';
782
- }
783
-
784
- static datum(
785
- hash: Credential,
786
- asset: string,
787
- mintedAmount: bigint,
788
- fees: CDPFees,
789
- ): Constr<Data> {
790
- return new Constr(0, [
791
- new Constr(0, [
792
- new Constr(0, [hash.hash]),
793
- fromText(asset),
794
- BigInt(mintedAmount),
795
- fees.type === 'ActiveCDPInterestTracking'
796
- ? new Constr(0, [
797
- BigInt(fees.last_settled),
798
- BigInt(fees.unitary_interest_snapshot),
799
- ])
800
- : new Constr(0, [
801
- BigInt(fees.lovelaces_treasury),
802
- BigInt(fees.lovelaces_indy_stakers),
803
- ]),
804
- ]),
805
- ]);
806
- }
807
-
808
657
  static validator(params: CdpParams): SpendingValidator {
809
658
  return {
810
659
  type: _cdpValidator.type,