@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.
- package/.github/workflows/ci.yml +8 -3
- package/dist/index.d.mts +1298 -677
- package/dist/index.d.ts +1298 -677
- package/dist/index.js +4650 -2217
- package/dist/index.mjs +4592 -2192
- package/eslint.config.mjs +7 -1
- package/package.json +9 -4
- package/src/contracts/cdp/helpers.ts +167 -0
- package/src/contracts/cdp/scripts.ts +33 -0
- package/src/contracts/cdp/transactions.ts +1310 -0
- package/src/contracts/cdp/types.ts +161 -0
- package/src/contracts/cdp-creator/scripts.ts +39 -0
- package/src/{types/indigo/cdp-creator.ts → contracts/cdp-creator/types.ts} +6 -4
- package/src/contracts/collector/scripts.ts +32 -0
- package/src/contracts/collector/transactions.ts +44 -0
- package/src/contracts/execute/scripts.ts +48 -0
- package/src/contracts/execute/types.ts +57 -0
- package/src/contracts/gov/helpers.ts +157 -0
- package/src/contracts/gov/scripts.ts +34 -0
- package/src/contracts/gov/transactions.ts +1224 -0
- package/src/contracts/gov/types-new.ts +115 -0
- package/src/contracts/gov/types.ts +89 -0
- package/src/{helpers/interest-oracle.ts → contracts/interest-oracle/helpers.ts} +37 -9
- package/src/contracts/interest-oracle/scripts.ts +18 -0
- package/src/contracts/interest-oracle/transactions.ts +149 -0
- package/src/{types/indigo/interest-oracle.ts → contracts/interest-oracle/types.ts} +1 -1
- package/src/contracts/lrp/scripts.ts +27 -0
- package/src/contracts/{lrp.ts → lrp/transactions.ts} +23 -23
- package/src/{types/indigo/lrp.ts → contracts/lrp/types.ts} +3 -3
- package/src/{scripts/one-shot-policy.ts → contracts/one-shot/scripts.ts} +1 -1
- package/src/contracts/{one-shot.ts → one-shot/transactions.ts} +3 -3
- package/src/contracts/poll/helpers.ts +55 -0
- package/src/contracts/poll/scripts.ts +72 -0
- package/src/contracts/poll/types-poll-manager.ts +38 -0
- package/src/contracts/poll/types-poll-shard.ts +38 -0
- package/src/contracts/poll/types-poll.ts +88 -0
- package/src/{scripts/price-oracle-validator.ts → contracts/price-oracle/scripts.ts} +1 -4
- package/src/contracts/price-oracle/transactions.ts +112 -0
- package/src/{types/indigo/price-oracle.ts → contracts/price-oracle/types.ts} +16 -4
- package/src/{helpers/stability-pool-helpers.ts → contracts/stability-pool/helpers.ts} +110 -6
- package/src/contracts/stability-pool/scripts.ts +46 -0
- package/src/contracts/stability-pool/transactions.ts +660 -0
- package/src/contracts/stability-pool/types-new.ts +208 -0
- package/src/contracts/stability-pool/types.ts +42 -0
- package/src/contracts/staking/helpers.ts +116 -0
- package/src/contracts/staking/scripts.ts +41 -0
- package/src/contracts/staking/transactions.ts +268 -0
- package/src/contracts/staking/types-new.ts +81 -0
- package/src/contracts/staking/types.ts +41 -0
- package/src/contracts/treasury/scripts.ts +37 -0
- package/src/contracts/treasury/transactions.ts +44 -0
- package/src/contracts/treasury/types.ts +55 -0
- package/src/contracts/version-registry/scripts.ts +29 -0
- package/src/contracts/version-registry/types-new.ts +19 -0
- package/src/{types/indigo/version-record.ts → contracts/version-registry/types.ts} +1 -1
- package/src/contracts/vesting/helpers.ts +267 -0
- package/src/index.ts +38 -33
- package/src/types/evolution-schema-options.ts +16 -0
- package/src/types/generic.ts +78 -60
- package/src/types/on-chain-decimal.ts +22 -0
- package/src/types/system-params.ts +22 -11
- package/src/utils/bigint-utils.ts +7 -0
- package/src/{helpers → utils}/helper-txs.ts +1 -0
- package/src/utils/time-helpers.ts +4 -0
- package/src/{helpers/helpers.ts → utils/utils.ts} +0 -10
- package/src/{helpers → utils}/value-helpers.ts +10 -0
- package/src/{scripts → validators}/cdp-creator-validator.ts +4 -50
- package/src/{scripts → validators}/cdp-validator.ts +3 -5
- package/src/{scripts → validators}/collector-validator.ts +2 -3
- package/src/{scripts/version-registry.ts → validators/execute-validator.ts} +3 -11
- package/src/{scripts/gov-validator.ts → validators/governance-validator.ts} +3 -40
- package/src/{scripts → validators}/interest-oracle-validator.ts +4 -20
- package/src/validators/lrp-validator.ts +7 -0
- package/src/validators/poll-manager-validator.ts +7 -0
- package/src/{scripts → validators}/poll-shard-validator.ts +3 -43
- package/src/{scripts → validators}/stability-pool-validator.ts +4 -57
- package/src/{scripts → validators}/staking-validator.ts +2 -3
- package/src/{scripts → validators}/treasury-validator.ts +2 -3
- package/src/{scripts → validators}/version-record-policy.ts +4 -23
- package/src/validators/version-registry-validator.ts +7 -0
- package/tests/cdp.test.ts +1565 -0
- package/tests/datums.test.ts +125 -108
- package/tests/endpoints/initialize.ts +240 -338
- package/tests/gov.test.ts +1874 -0
- package/tests/hash-checks.test.ts +26 -21
- package/tests/indigo-test-helpers.ts +1 -55
- package/tests/initialize.test.ts +10 -5
- package/tests/interest-calculations.test.ts +18 -18
- package/tests/interest-oracle.test.ts +20 -18
- package/tests/lrp.test.ts +180 -78
- package/tests/mock/assets-mock.ts +59 -0
- package/tests/queries/cdp-queries.ts +144 -0
- package/tests/queries/collector-queries.ts +26 -0
- package/tests/queries/execute-queries.ts +46 -0
- package/tests/queries/governance-queries.ts +19 -16
- package/tests/queries/iasset-queries.ts +46 -23
- package/tests/queries/interest-oracle-queries.ts +3 -6
- package/tests/queries/lrp-queries.ts +2 -2
- package/tests/queries/poll-queries.ts +97 -0
- package/tests/queries/price-oracle-queries.ts +5 -22
- package/tests/queries/stability-pool-queries.ts +10 -8
- package/tests/queries/staking-queries.ts +28 -19
- package/tests/queries/treasury-queries.ts +19 -0
- package/tests/stability-pool.test.ts +186 -71
- package/tests/staking.test.ts +30 -23
- package/tests/test-helpers.ts +11 -2
- package/tests/utils/asserts.ts +13 -0
- package/tests/utils/index.ts +50 -0
- package/tsconfig.json +3 -1
- package/vitest.config.ts +1 -1
- package/.github/workflows/test.yml +0 -44
- package/src/contracts/cdp.ts +0 -748
- package/src/contracts/collector.ts +0 -98
- package/src/contracts/gov.ts +0 -1
- package/src/contracts/interest-oracle.ts +0 -149
- package/src/contracts/stability-pool.ts +0 -692
- package/src/contracts/staking.ts +0 -348
- package/src/contracts/treasury.ts +0 -112
- package/src/helpers/asset-helpers.ts +0 -57
- package/src/helpers/staking-helpers.ts +0 -94
- package/src/helpers/time-helpers.ts +0 -4
- package/src/scripts/execute-validator.ts +0 -52
- package/src/scripts/lrp-validator.ts +0 -40
- package/src/scripts/poll-manager-validator.ts +0 -52
- package/src/types/indigo/cdp.ts +0 -88
- package/src/types/indigo/execute.ts +0 -21
- package/src/types/indigo/gov.ts +0 -51
- package/src/types/indigo/poll-manager.ts +0 -21
- package/src/types/indigo/poll-shard.ts +0 -16
- package/src/types/indigo/stability-pool.ts +0 -233
- package/src/types/indigo/staking.ts +0 -99
- /package/src/{types/one-shot.ts → contracts/one-shot/types.ts} +0 -0
- /package/src/{helpers/price-oracle-helpers.ts → contracts/price-oracle/helpers.ts} +0 -0
- /package/src/{helpers → utils}/indigo-helpers.ts +0 -0
- /package/src/{helpers → utils}/lucid-utils.ts +0 -0
|
@@ -0,0 +1,1310 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addAssets,
|
|
3
|
+
Assets,
|
|
4
|
+
Data,
|
|
5
|
+
LucidEvolution,
|
|
6
|
+
OutRef,
|
|
7
|
+
slotToUnixTime,
|
|
8
|
+
TxBuilder,
|
|
9
|
+
UTxO,
|
|
10
|
+
} from '@lucid-evolution/lucid';
|
|
11
|
+
import {
|
|
12
|
+
fromSystemParamsAsset,
|
|
13
|
+
fromSystemParamsScriptRef,
|
|
14
|
+
SystemParams,
|
|
15
|
+
} from '../../types/system-params';
|
|
16
|
+
import {
|
|
17
|
+
addrDetails,
|
|
18
|
+
createScriptAddress,
|
|
19
|
+
getInlineDatumOrThrow,
|
|
20
|
+
} from '../../utils/lucid-utils';
|
|
21
|
+
import { matchSingle } from '../../utils/utils';
|
|
22
|
+
import {
|
|
23
|
+
CDPContent,
|
|
24
|
+
parseCdpDatumOrThrow,
|
|
25
|
+
parseIAssetDatumOrThrow,
|
|
26
|
+
serialiseCdpDatum,
|
|
27
|
+
serialiseCdpRedeemer,
|
|
28
|
+
} from './types';
|
|
29
|
+
import { parsePriceOracleDatum } from '../price-oracle/types';
|
|
30
|
+
import { parseInterestOracleDatum } from '../interest-oracle/types';
|
|
31
|
+
import { parseGovDatumOrThrow } from '../gov/types';
|
|
32
|
+
import {
|
|
33
|
+
calculateAccruedInterest,
|
|
34
|
+
calculateUnitaryInterestSinceOracleLastUpdated,
|
|
35
|
+
computeInterestLovelacesFor100PercentCR,
|
|
36
|
+
} from '../interest-oracle/helpers';
|
|
37
|
+
import { oracleExpirationAwareValidity } from '../price-oracle/helpers';
|
|
38
|
+
import { match, P } from 'ts-pattern';
|
|
39
|
+
import { serialiseCDPCreatorRedeemer } from '../cdp-creator/types';
|
|
40
|
+
import {
|
|
41
|
+
assetClassValueOf,
|
|
42
|
+
lovelacesAmt,
|
|
43
|
+
mkAssetsOf,
|
|
44
|
+
mkLovelacesOf,
|
|
45
|
+
} from '../../utils/value-helpers';
|
|
46
|
+
import { calculateMinCollateralCappedIAssetRedemptionAmt } from './helpers';
|
|
47
|
+
import { bigintMin } from '../../utils/bigint-utils';
|
|
48
|
+
import { ocdMul } from '../../types/on-chain-decimal';
|
|
49
|
+
import {
|
|
50
|
+
parseStabilityPoolDatum,
|
|
51
|
+
serialiseStabilityPoolDatum,
|
|
52
|
+
serialiseStabilityPoolRedeemer,
|
|
53
|
+
} from '../stability-pool/types-new';
|
|
54
|
+
import { liquidationHelper } from '../stability-pool/helpers';
|
|
55
|
+
import { array as A, function as F } from 'fp-ts';
|
|
56
|
+
import { calculateFeeFromPercentage } from '../../utils/indigo-helpers';
|
|
57
|
+
import { collectorFeeTx } from '../collector/transactions';
|
|
58
|
+
import { treasuryFeeTx } from '../treasury/transactions';
|
|
59
|
+
|
|
60
|
+
export async function openCdp(
|
|
61
|
+
collateralAmount: bigint,
|
|
62
|
+
mintedAmount: bigint,
|
|
63
|
+
sysParams: SystemParams,
|
|
64
|
+
cdpCreatorOref: OutRef,
|
|
65
|
+
iassetOref: OutRef,
|
|
66
|
+
priceOracleOref: OutRef,
|
|
67
|
+
interestOracleOref: OutRef,
|
|
68
|
+
collectorOref: OutRef,
|
|
69
|
+
lucid: LucidEvolution,
|
|
70
|
+
currentSlot: number,
|
|
71
|
+
): Promise<TxBuilder> {
|
|
72
|
+
const network = lucid.config().network!;
|
|
73
|
+
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
|
|
74
|
+
|
|
75
|
+
const [pkh, skh] = await addrDetails(lucid);
|
|
76
|
+
|
|
77
|
+
const cdpCreatorRefScriptUtxo = matchSingle(
|
|
78
|
+
await lucid.utxosByOutRef([
|
|
79
|
+
fromSystemParamsScriptRef(
|
|
80
|
+
sysParams.scriptReferences.cdpCreatorValidatorRef,
|
|
81
|
+
),
|
|
82
|
+
]),
|
|
83
|
+
(_) => new Error('Expected a single cdp creator Ref Script UTXO'),
|
|
84
|
+
);
|
|
85
|
+
const cdpAuthTokenPolicyRefScriptUtxo = matchSingle(
|
|
86
|
+
await lucid.utxosByOutRef([
|
|
87
|
+
fromSystemParamsScriptRef(
|
|
88
|
+
sysParams.scriptReferences.authTokenPolicies.cdpAuthTokenRef,
|
|
89
|
+
),
|
|
90
|
+
]),
|
|
91
|
+
(_) => new Error('Expected a single cdp auth token policy Ref Script UTXO'),
|
|
92
|
+
);
|
|
93
|
+
const iAssetTokenPolicyRefScriptUtxo = matchSingle(
|
|
94
|
+
await lucid.utxosByOutRef([
|
|
95
|
+
fromSystemParamsScriptRef(
|
|
96
|
+
sysParams.scriptReferences.iAssetTokenPolicyRef,
|
|
97
|
+
),
|
|
98
|
+
]),
|
|
99
|
+
(_) => new Error('Expected a single iasset token policy Ref Script UTXO'),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const iassetUtxo = matchSingle(
|
|
103
|
+
await lucid.utxosByOutRef([iassetOref]),
|
|
104
|
+
(_) => new Error('Expected a single iasset UTXO'),
|
|
105
|
+
);
|
|
106
|
+
const iassetDatum = parseIAssetDatumOrThrow(
|
|
107
|
+
getInlineDatumOrThrow(iassetUtxo),
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const priceOracleUtxo = matchSingle(
|
|
111
|
+
await lucid.utxosByOutRef([priceOracleOref]),
|
|
112
|
+
(_) => new Error('Expected a single price oracle UTXO'),
|
|
113
|
+
);
|
|
114
|
+
const priceOracleDatum = parsePriceOracleDatum(
|
|
115
|
+
getInlineDatumOrThrow(priceOracleUtxo),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const interestOracleUtxo = matchSingle(
|
|
119
|
+
await lucid.utxosByOutRef([interestOracleOref]),
|
|
120
|
+
(_) => new Error('Expected a single interest oracle UTXO'),
|
|
121
|
+
);
|
|
122
|
+
const interestOracleDatum = parseInterestOracleDatum(
|
|
123
|
+
getInlineDatumOrThrow(interestOracleUtxo),
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const cdpCreatorUtxo = matchSingle(
|
|
127
|
+
await lucid.utxosByOutRef([cdpCreatorOref]),
|
|
128
|
+
(_) => new Error('Expected a single CDP creator UTXO'),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
match(iassetDatum.price)
|
|
132
|
+
.with({ Delisted: P.any }, () => {
|
|
133
|
+
throw new Error("Can't open CDP of delisted asset");
|
|
134
|
+
})
|
|
135
|
+
.otherwise(() => {});
|
|
136
|
+
|
|
137
|
+
const cdpNftVal = mkAssetsOf(
|
|
138
|
+
fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
|
|
139
|
+
1n,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const iassetTokensVal = mkAssetsOf(
|
|
143
|
+
{
|
|
144
|
+
currencySymbol: sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
|
|
145
|
+
tokenName: iassetDatum.assetName,
|
|
146
|
+
},
|
|
147
|
+
mintedAmount,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const txValidity = oracleExpirationAwareValidity(
|
|
151
|
+
currentSlot,
|
|
152
|
+
Number(sysParams.cdpCreatorParams.biasTime),
|
|
153
|
+
Number(priceOracleDatum.expiration),
|
|
154
|
+
network,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const tx = lucid
|
|
158
|
+
.newTx()
|
|
159
|
+
.validFrom(txValidity.validFrom)
|
|
160
|
+
.validTo(txValidity.validTo)
|
|
161
|
+
.readFrom([
|
|
162
|
+
cdpCreatorRefScriptUtxo,
|
|
163
|
+
cdpAuthTokenPolicyRefScriptUtxo,
|
|
164
|
+
iAssetTokenPolicyRefScriptUtxo,
|
|
165
|
+
])
|
|
166
|
+
.mintAssets(cdpNftVal, Data.void())
|
|
167
|
+
.mintAssets(iassetTokensVal, Data.void())
|
|
168
|
+
.collectFrom(
|
|
169
|
+
[cdpCreatorUtxo],
|
|
170
|
+
serialiseCDPCreatorRedeemer({
|
|
171
|
+
CreateCDP: {
|
|
172
|
+
cdpOwner: pkh.hash,
|
|
173
|
+
minted: mintedAmount,
|
|
174
|
+
collateral: collateralAmount,
|
|
175
|
+
currentTime: currentTime,
|
|
176
|
+
},
|
|
177
|
+
}),
|
|
178
|
+
)
|
|
179
|
+
.pay.ToContract(
|
|
180
|
+
createScriptAddress(network, sysParams.validatorHashes.cdpHash, skh),
|
|
181
|
+
{
|
|
182
|
+
kind: 'inline',
|
|
183
|
+
value: serialiseCdpDatum({
|
|
184
|
+
cdpOwner: pkh.hash,
|
|
185
|
+
iasset: iassetDatum.assetName,
|
|
186
|
+
mintedAmt: mintedAmount,
|
|
187
|
+
cdpFees: {
|
|
188
|
+
ActiveCDPInterestTracking: {
|
|
189
|
+
lastSettled: currentTime,
|
|
190
|
+
unitaryInterestSnapshot:
|
|
191
|
+
calculateUnitaryInterestSinceOracleLastUpdated(
|
|
192
|
+
currentTime,
|
|
193
|
+
interestOracleDatum,
|
|
194
|
+
) + interestOracleDatum.unitaryInterest,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
}),
|
|
198
|
+
},
|
|
199
|
+
addAssets(cdpNftVal, mkLovelacesOf(collateralAmount)),
|
|
200
|
+
)
|
|
201
|
+
.pay.ToContract(
|
|
202
|
+
cdpCreatorUtxo.address,
|
|
203
|
+
{ kind: 'inline', value: Data.void() },
|
|
204
|
+
cdpCreatorUtxo.assets,
|
|
205
|
+
)
|
|
206
|
+
.readFrom([priceOracleUtxo, interestOracleUtxo, iassetUtxo])
|
|
207
|
+
.addSignerKey(pkh.hash);
|
|
208
|
+
|
|
209
|
+
const debtMintingFee = calculateFeeFromPercentage(
|
|
210
|
+
iassetDatum.debtMintingFeePercentage,
|
|
211
|
+
(mintedAmount * priceOracleDatum.price.getOnChainInt) / 1_000_000n,
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
if (debtMintingFee > 0) {
|
|
215
|
+
await collectorFeeTx(debtMintingFee, lucid, sysParams, tx, collectorOref);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return tx;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function adjustCdp(
|
|
222
|
+
collateralAmount: bigint,
|
|
223
|
+
mintAmount: bigint,
|
|
224
|
+
cdpOref: OutRef,
|
|
225
|
+
iassetOref: OutRef,
|
|
226
|
+
priceOracleOref: OutRef,
|
|
227
|
+
interestOracleOref: OutRef,
|
|
228
|
+
collectorOref: OutRef,
|
|
229
|
+
govOref: OutRef,
|
|
230
|
+
treasuryOref: OutRef,
|
|
231
|
+
sysParams: SystemParams,
|
|
232
|
+
lucid: LucidEvolution,
|
|
233
|
+
currentSlot: number,
|
|
234
|
+
): Promise<TxBuilder> {
|
|
235
|
+
const network = lucid.config().network!;
|
|
236
|
+
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
|
|
237
|
+
|
|
238
|
+
const cdpRefScriptUtxo = matchSingle(
|
|
239
|
+
await lucid.utxosByOutRef([
|
|
240
|
+
fromSystemParamsScriptRef(sysParams.scriptReferences.cdpValidatorRef),
|
|
241
|
+
]),
|
|
242
|
+
(_) => new Error('Expected a single cdp Ref Script UTXO'),
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const cdpUtxo = matchSingle(
|
|
246
|
+
await lucid.utxosByOutRef([cdpOref]),
|
|
247
|
+
(_) => new Error('Expected a single cdp UTXO'),
|
|
248
|
+
);
|
|
249
|
+
const cdpDatum = parseCdpDatumOrThrow(getInlineDatumOrThrow(cdpUtxo));
|
|
250
|
+
|
|
251
|
+
const iassetUtxo = matchSingle(
|
|
252
|
+
await lucid.utxosByOutRef([iassetOref]),
|
|
253
|
+
(_) => new Error('Expected a single iasset UTXO'),
|
|
254
|
+
);
|
|
255
|
+
const iassetDatum = parseIAssetDatumOrThrow(
|
|
256
|
+
getInlineDatumOrThrow(iassetUtxo),
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const govUtxo = matchSingle(
|
|
260
|
+
await lucid.utxosByOutRef([govOref]),
|
|
261
|
+
(_) => new Error('Expected a single gov UTXO'),
|
|
262
|
+
);
|
|
263
|
+
const govDatum = parseGovDatumOrThrow(getInlineDatumOrThrow(govUtxo));
|
|
264
|
+
|
|
265
|
+
const priceOracleUtxo = matchSingle(
|
|
266
|
+
await lucid.utxosByOutRef([priceOracleOref]),
|
|
267
|
+
(_) => new Error('Expected a single price oracle UTXO'),
|
|
268
|
+
);
|
|
269
|
+
const priceOracleDatum = parsePriceOracleDatum(
|
|
270
|
+
getInlineDatumOrThrow(priceOracleUtxo),
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
const interestOracleUtxo = matchSingle(
|
|
274
|
+
await lucid.utxosByOutRef([interestOracleOref]),
|
|
275
|
+
(_) => new Error('Expected a single interest oracle UTXO'),
|
|
276
|
+
);
|
|
277
|
+
const interestOracleDatum = parseInterestOracleDatum(
|
|
278
|
+
getInlineDatumOrThrow(interestOracleUtxo),
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
match(iassetDatum.price)
|
|
282
|
+
.with({ Delisted: P.any }, () => {
|
|
283
|
+
throw new Error("Can't adjust CDP of delisted asset");
|
|
284
|
+
})
|
|
285
|
+
.otherwise(() => {});
|
|
286
|
+
|
|
287
|
+
const txValidity = oracleExpirationAwareValidity(
|
|
288
|
+
currentSlot,
|
|
289
|
+
Number(sysParams.cdpCreatorParams.biasTime),
|
|
290
|
+
Number(priceOracleDatum.expiration),
|
|
291
|
+
network,
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
const tx = lucid
|
|
295
|
+
.newTx()
|
|
296
|
+
.validFrom(txValidity.validFrom)
|
|
297
|
+
.validTo(txValidity.validTo)
|
|
298
|
+
.collectFrom(
|
|
299
|
+
[cdpUtxo],
|
|
300
|
+
serialiseCdpRedeemer({
|
|
301
|
+
AdjustCdp: {
|
|
302
|
+
collateralAmtChange: collateralAmount,
|
|
303
|
+
currentTime: currentTime,
|
|
304
|
+
mintedAmtChange: mintAmount,
|
|
305
|
+
},
|
|
306
|
+
}),
|
|
307
|
+
)
|
|
308
|
+
.readFrom([cdpRefScriptUtxo])
|
|
309
|
+
.readFrom([iassetUtxo, govUtxo, priceOracleUtxo, interestOracleUtxo])
|
|
310
|
+
.pay.ToContract(
|
|
311
|
+
cdpUtxo.address,
|
|
312
|
+
{
|
|
313
|
+
kind: 'inline',
|
|
314
|
+
value: serialiseCdpDatum({
|
|
315
|
+
...cdpDatum,
|
|
316
|
+
mintedAmt: cdpDatum.mintedAmt + mintAmount,
|
|
317
|
+
cdpFees: {
|
|
318
|
+
ActiveCDPInterestTracking: {
|
|
319
|
+
lastSettled: currentTime,
|
|
320
|
+
unitaryInterestSnapshot:
|
|
321
|
+
calculateUnitaryInterestSinceOracleLastUpdated(
|
|
322
|
+
currentTime,
|
|
323
|
+
interestOracleDatum,
|
|
324
|
+
) + interestOracleDatum.unitaryInterest,
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
}),
|
|
328
|
+
},
|
|
329
|
+
addAssets(cdpUtxo.assets, mkLovelacesOf(collateralAmount)),
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
if (!cdpDatum.cdpOwner) {
|
|
333
|
+
throw new Error('Expected active CDP');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
tx.addSignerKey(cdpDatum.cdpOwner);
|
|
337
|
+
|
|
338
|
+
if (mintAmount !== 0n) {
|
|
339
|
+
const iAssetTokenPolicyRefScriptUtxo = matchSingle(
|
|
340
|
+
await lucid.utxosByOutRef([
|
|
341
|
+
fromSystemParamsScriptRef(
|
|
342
|
+
sysParams.scriptReferences.iAssetTokenPolicyRef,
|
|
343
|
+
),
|
|
344
|
+
]),
|
|
345
|
+
(_) => new Error('Expected a single iasset token policy Ref Script UTXO'),
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
const iassetTokensVal = mkAssetsOf(
|
|
349
|
+
{
|
|
350
|
+
currencySymbol: sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
|
|
351
|
+
tokenName: iassetDatum.assetName,
|
|
352
|
+
},
|
|
353
|
+
mintAmount,
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
tx.readFrom([iAssetTokenPolicyRefScriptUtxo]).mintAssets(
|
|
357
|
+
iassetTokensVal,
|
|
358
|
+
Data.void(),
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const interestAdaAmt = match(cdpDatum.cdpFees)
|
|
363
|
+
.with({ FrozenCDPAccumulatedFees: P.any }, () => {
|
|
364
|
+
throw new Error('CDP fees wrong');
|
|
365
|
+
})
|
|
366
|
+
.with({ ActiveCDPInterestTracking: P.select() }, (interest) => {
|
|
367
|
+
const interestPaymentIAssetAmt = calculateAccruedInterest(
|
|
368
|
+
currentTime,
|
|
369
|
+
interest.unitaryInterestSnapshot,
|
|
370
|
+
cdpDatum.mintedAmt,
|
|
371
|
+
interest.lastSettled,
|
|
372
|
+
interestOracleDatum,
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
return (
|
|
376
|
+
(interestPaymentIAssetAmt * priceOracleDatum.price.getOnChainInt) /
|
|
377
|
+
1_000_000n
|
|
378
|
+
);
|
|
379
|
+
})
|
|
380
|
+
.exhaustive();
|
|
381
|
+
|
|
382
|
+
const interestCollectorAdaAmt = calculateFeeFromPercentage(
|
|
383
|
+
iassetDatum.interestCollectorPortionPercentage,
|
|
384
|
+
interestAdaAmt,
|
|
385
|
+
);
|
|
386
|
+
const interestTreasuryAdaAmt = interestAdaAmt - interestCollectorAdaAmt;
|
|
387
|
+
|
|
388
|
+
if (interestTreasuryAdaAmt > 0) {
|
|
389
|
+
await treasuryFeeTx(
|
|
390
|
+
interestTreasuryAdaAmt,
|
|
391
|
+
lucid,
|
|
392
|
+
sysParams,
|
|
393
|
+
tx,
|
|
394
|
+
treasuryOref,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
let collectorFee = interestCollectorAdaAmt;
|
|
399
|
+
|
|
400
|
+
// when mint
|
|
401
|
+
if (mintAmount > 0n) {
|
|
402
|
+
collectorFee += calculateFeeFromPercentage(
|
|
403
|
+
iassetDatum.debtMintingFeePercentage,
|
|
404
|
+
(mintAmount * priceOracleDatum.price.getOnChainInt) / 1_000_000n,
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// when withdraw
|
|
409
|
+
if (collateralAmount < 0n) {
|
|
410
|
+
collectorFee += calculateFeeFromPercentage(
|
|
411
|
+
govDatum.protocolParams.collateralFeePercentage,
|
|
412
|
+
-collateralAmount,
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (collectorFee > 0n) {
|
|
417
|
+
await collectorFeeTx(collectorFee, lucid, sysParams, tx, collectorOref);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return tx;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export async function depositCdp(
|
|
424
|
+
amount: bigint,
|
|
425
|
+
cdpOref: OutRef,
|
|
426
|
+
iassetOref: OutRef,
|
|
427
|
+
priceOracleOref: OutRef,
|
|
428
|
+
interestOracleOref: OutRef,
|
|
429
|
+
collectorOref: OutRef,
|
|
430
|
+
govOref: OutRef,
|
|
431
|
+
treasuryOref: OutRef,
|
|
432
|
+
params: SystemParams,
|
|
433
|
+
lucid: LucidEvolution,
|
|
434
|
+
currentSlot: number,
|
|
435
|
+
): Promise<TxBuilder> {
|
|
436
|
+
return adjustCdp(
|
|
437
|
+
amount,
|
|
438
|
+
0n,
|
|
439
|
+
cdpOref,
|
|
440
|
+
iassetOref,
|
|
441
|
+
priceOracleOref,
|
|
442
|
+
interestOracleOref,
|
|
443
|
+
collectorOref,
|
|
444
|
+
govOref,
|
|
445
|
+
treasuryOref,
|
|
446
|
+
params,
|
|
447
|
+
lucid,
|
|
448
|
+
currentSlot,
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export async function withdrawCdp(
|
|
453
|
+
amount: bigint,
|
|
454
|
+
cdpOref: OutRef,
|
|
455
|
+
iassetOref: OutRef,
|
|
456
|
+
priceOracleOref: OutRef,
|
|
457
|
+
interestOracleOref: OutRef,
|
|
458
|
+
collectorOref: OutRef,
|
|
459
|
+
govOref: OutRef,
|
|
460
|
+
treasuryOref: OutRef,
|
|
461
|
+
params: SystemParams,
|
|
462
|
+
lucid: LucidEvolution,
|
|
463
|
+
currentSlot: number,
|
|
464
|
+
): Promise<TxBuilder> {
|
|
465
|
+
return adjustCdp(
|
|
466
|
+
-amount,
|
|
467
|
+
0n,
|
|
468
|
+
cdpOref,
|
|
469
|
+
iassetOref,
|
|
470
|
+
priceOracleOref,
|
|
471
|
+
interestOracleOref,
|
|
472
|
+
collectorOref,
|
|
473
|
+
govOref,
|
|
474
|
+
treasuryOref,
|
|
475
|
+
params,
|
|
476
|
+
lucid,
|
|
477
|
+
currentSlot,
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export async function mintCdp(
|
|
482
|
+
amount: bigint,
|
|
483
|
+
cdpOref: OutRef,
|
|
484
|
+
iassetOref: OutRef,
|
|
485
|
+
priceOracleOref: OutRef,
|
|
486
|
+
interestOracleOref: OutRef,
|
|
487
|
+
collectorOref: OutRef,
|
|
488
|
+
govOref: OutRef,
|
|
489
|
+
treasuryOref: OutRef,
|
|
490
|
+
params: SystemParams,
|
|
491
|
+
lucid: LucidEvolution,
|
|
492
|
+
currentSlot: number,
|
|
493
|
+
): Promise<TxBuilder> {
|
|
494
|
+
return adjustCdp(
|
|
495
|
+
0n,
|
|
496
|
+
amount,
|
|
497
|
+
cdpOref,
|
|
498
|
+
iassetOref,
|
|
499
|
+
priceOracleOref,
|
|
500
|
+
interestOracleOref,
|
|
501
|
+
collectorOref,
|
|
502
|
+
govOref,
|
|
503
|
+
treasuryOref,
|
|
504
|
+
params,
|
|
505
|
+
lucid,
|
|
506
|
+
currentSlot,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export async function burnCdp(
|
|
511
|
+
amount: bigint,
|
|
512
|
+
cdpOref: OutRef,
|
|
513
|
+
iassetOref: OutRef,
|
|
514
|
+
priceOracleOref: OutRef,
|
|
515
|
+
interestOracleOref: OutRef,
|
|
516
|
+
collectorOref: OutRef,
|
|
517
|
+
govOref: OutRef,
|
|
518
|
+
treasuryOref: OutRef,
|
|
519
|
+
params: SystemParams,
|
|
520
|
+
lucid: LucidEvolution,
|
|
521
|
+
currentSlot: number,
|
|
522
|
+
): Promise<TxBuilder> {
|
|
523
|
+
return adjustCdp(
|
|
524
|
+
0n,
|
|
525
|
+
-amount,
|
|
526
|
+
cdpOref,
|
|
527
|
+
iassetOref,
|
|
528
|
+
priceOracleOref,
|
|
529
|
+
interestOracleOref,
|
|
530
|
+
collectorOref,
|
|
531
|
+
govOref,
|
|
532
|
+
treasuryOref,
|
|
533
|
+
params,
|
|
534
|
+
lucid,
|
|
535
|
+
currentSlot,
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export async function closeCdp(
|
|
540
|
+
cdpOref: OutRef,
|
|
541
|
+
iassetOref: OutRef,
|
|
542
|
+
priceOracleOref: OutRef,
|
|
543
|
+
interestOracleOref: OutRef,
|
|
544
|
+
collectorOref: OutRef,
|
|
545
|
+
govOref: OutRef,
|
|
546
|
+
treasuryOref: OutRef,
|
|
547
|
+
sysParams: SystemParams,
|
|
548
|
+
lucid: LucidEvolution,
|
|
549
|
+
currentSlot: number,
|
|
550
|
+
): Promise<TxBuilder> {
|
|
551
|
+
const network = lucid.config().network!;
|
|
552
|
+
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
|
|
553
|
+
|
|
554
|
+
const cdpRefScriptUtxo = matchSingle(
|
|
555
|
+
await lucid.utxosByOutRef([
|
|
556
|
+
fromSystemParamsScriptRef(sysParams.scriptReferences.cdpValidatorRef),
|
|
557
|
+
]),
|
|
558
|
+
(_) => new Error('Expected a single cdp Ref Script UTXO'),
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
const cdpAuthTokenPolicyRefScriptUtxo = matchSingle(
|
|
562
|
+
await lucid.utxosByOutRef([
|
|
563
|
+
fromSystemParamsScriptRef(
|
|
564
|
+
sysParams.scriptReferences.authTokenPolicies.cdpAuthTokenRef,
|
|
565
|
+
),
|
|
566
|
+
]),
|
|
567
|
+
(_) => new Error('Expected a single cdp auth token policy Ref Script UTXO'),
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
const iAssetTokenPolicyRefScriptUtxo = matchSingle(
|
|
571
|
+
await lucid.utxosByOutRef([
|
|
572
|
+
fromSystemParamsScriptRef(
|
|
573
|
+
sysParams.scriptReferences.iAssetTokenPolicyRef,
|
|
574
|
+
),
|
|
575
|
+
]),
|
|
576
|
+
(_) => new Error('Expected a single iasset token policy Ref Script UTXO'),
|
|
577
|
+
);
|
|
578
|
+
|
|
579
|
+
const cdpUtxo = matchSingle(
|
|
580
|
+
await lucid.utxosByOutRef([cdpOref]),
|
|
581
|
+
(_) => new Error('Expected a single cdp UTXO'),
|
|
582
|
+
);
|
|
583
|
+
const cdpDatum = parseCdpDatumOrThrow(getInlineDatumOrThrow(cdpUtxo));
|
|
584
|
+
|
|
585
|
+
const iassetUtxo = matchSingle(
|
|
586
|
+
await lucid.utxosByOutRef([iassetOref]),
|
|
587
|
+
(_) => new Error('Expected a single iasset UTXO'),
|
|
588
|
+
);
|
|
589
|
+
const iassetDatum = parseIAssetDatumOrThrow(
|
|
590
|
+
getInlineDatumOrThrow(iassetUtxo),
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
const govUtxo = matchSingle(
|
|
594
|
+
await lucid.utxosByOutRef([govOref]),
|
|
595
|
+
(_) => new Error('Expected a single gov UTXO'),
|
|
596
|
+
);
|
|
597
|
+
const govDatum = parseGovDatumOrThrow(getInlineDatumOrThrow(govUtxo));
|
|
598
|
+
|
|
599
|
+
const priceOracleUtxo = matchSingle(
|
|
600
|
+
await lucid.utxosByOutRef([priceOracleOref]),
|
|
601
|
+
(_) => new Error('Expected a single price oracle UTXO'),
|
|
602
|
+
);
|
|
603
|
+
const priceOracleDatum = parsePriceOracleDatum(
|
|
604
|
+
getInlineDatumOrThrow(priceOracleUtxo),
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
const interestOracleUtxo = matchSingle(
|
|
608
|
+
await lucid.utxosByOutRef([interestOracleOref]),
|
|
609
|
+
(_) => new Error('Expected a single interest oracle UTXO'),
|
|
610
|
+
);
|
|
611
|
+
const interestOracleDatum = parseInterestOracleDatum(
|
|
612
|
+
getInlineDatumOrThrow(interestOracleUtxo),
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
const txValidity = oracleExpirationAwareValidity(
|
|
616
|
+
currentSlot,
|
|
617
|
+
Number(sysParams.cdpCreatorParams.biasTime),
|
|
618
|
+
Number(priceOracleDatum.expiration),
|
|
619
|
+
network,
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
const tx = lucid
|
|
623
|
+
.newTx()
|
|
624
|
+
.readFrom([
|
|
625
|
+
cdpRefScriptUtxo,
|
|
626
|
+
iAssetTokenPolicyRefScriptUtxo,
|
|
627
|
+
cdpAuthTokenPolicyRefScriptUtxo,
|
|
628
|
+
])
|
|
629
|
+
.readFrom([iassetUtxo, govUtxo, priceOracleUtxo, interestOracleUtxo])
|
|
630
|
+
.validFrom(txValidity.validFrom)
|
|
631
|
+
.validTo(txValidity.validTo)
|
|
632
|
+
.mintAssets(
|
|
633
|
+
mkAssetsOf(
|
|
634
|
+
{
|
|
635
|
+
currencySymbol: sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
|
|
636
|
+
tokenName: iassetDatum.assetName,
|
|
637
|
+
},
|
|
638
|
+
-cdpDatum.mintedAmt,
|
|
639
|
+
),
|
|
640
|
+
Data.void(),
|
|
641
|
+
)
|
|
642
|
+
.mintAssets(
|
|
643
|
+
mkAssetsOf(fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken), -1n),
|
|
644
|
+
Data.void(),
|
|
645
|
+
)
|
|
646
|
+
.collectFrom(
|
|
647
|
+
[cdpUtxo],
|
|
648
|
+
serialiseCdpRedeemer({ CloseCdp: { currentTime: currentTime } }),
|
|
649
|
+
);
|
|
650
|
+
|
|
651
|
+
if (!cdpDatum.cdpOwner) {
|
|
652
|
+
throw new Error('Expected active CDP');
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
tx.addSignerKey(cdpDatum.cdpOwner);
|
|
656
|
+
|
|
657
|
+
const interestAdaAmt = match(cdpDatum.cdpFees)
|
|
658
|
+
.with({ FrozenCDPAccumulatedFees: P.any }, () => {
|
|
659
|
+
throw new Error('CDP fees wrong');
|
|
660
|
+
})
|
|
661
|
+
.with({ ActiveCDPInterestTracking: P.select() }, (interest) => {
|
|
662
|
+
const interestPaymentIAssetAmt = calculateAccruedInterest(
|
|
663
|
+
currentTime,
|
|
664
|
+
interest.unitaryInterestSnapshot,
|
|
665
|
+
cdpDatum.mintedAmt,
|
|
666
|
+
interest.lastSettled,
|
|
667
|
+
interestOracleDatum,
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
return (
|
|
671
|
+
(interestPaymentIAssetAmt * priceOracleDatum.price.getOnChainInt) /
|
|
672
|
+
1_000_000n
|
|
673
|
+
);
|
|
674
|
+
})
|
|
675
|
+
.exhaustive();
|
|
676
|
+
|
|
677
|
+
const interestCollectorAdaAmt = calculateFeeFromPercentage(
|
|
678
|
+
iassetDatum.interestCollectorPortionPercentage,
|
|
679
|
+
interestAdaAmt,
|
|
680
|
+
);
|
|
681
|
+
const interestTreasuryAdaAmt = interestAdaAmt - interestCollectorAdaAmt;
|
|
682
|
+
|
|
683
|
+
if (interestTreasuryAdaAmt > 0) {
|
|
684
|
+
await treasuryFeeTx(
|
|
685
|
+
interestTreasuryAdaAmt,
|
|
686
|
+
lucid,
|
|
687
|
+
sysParams,
|
|
688
|
+
tx,
|
|
689
|
+
treasuryOref,
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const collectorFee =
|
|
694
|
+
interestCollectorAdaAmt +
|
|
695
|
+
calculateFeeFromPercentage(
|
|
696
|
+
govDatum.protocolParams.collateralFeePercentage,
|
|
697
|
+
lovelacesAmt(cdpUtxo.assets) - interestAdaAmt,
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
if (collectorFee > 0n) {
|
|
701
|
+
await collectorFeeTx(collectorFee, lucid, sysParams, tx, collectorOref);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
return tx;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
export async function redeemCdp(
|
|
708
|
+
/**
|
|
709
|
+
* When the goal is to redeem the maximum possible, just pass in the total minted amount of the CDP.
|
|
710
|
+
* The logic will automatically cap the amount to the max.
|
|
711
|
+
*/
|
|
712
|
+
attemptedRedemptionIAssetAmt: bigint,
|
|
713
|
+
cdpOref: OutRef,
|
|
714
|
+
iassetOref: OutRef,
|
|
715
|
+
priceOracleOref: OutRef,
|
|
716
|
+
interestOracleOref: OutRef,
|
|
717
|
+
collectorOref: OutRef,
|
|
718
|
+
treasuryOref: OutRef,
|
|
719
|
+
sysParams: SystemParams,
|
|
720
|
+
lucid: LucidEvolution,
|
|
721
|
+
currentSlot: number,
|
|
722
|
+
): Promise<TxBuilder> {
|
|
723
|
+
const network = lucid.config().network!;
|
|
724
|
+
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
|
|
725
|
+
|
|
726
|
+
const cdpRefScriptUtxo = matchSingle(
|
|
727
|
+
await lucid.utxosByOutRef([
|
|
728
|
+
fromSystemParamsScriptRef(sysParams.scriptReferences.cdpValidatorRef),
|
|
729
|
+
]),
|
|
730
|
+
(_) => new Error('Expected a single cdp Ref Script UTXO'),
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
const iAssetTokenPolicyRefScriptUtxo = matchSingle(
|
|
734
|
+
await lucid.utxosByOutRef([
|
|
735
|
+
fromSystemParamsScriptRef(
|
|
736
|
+
sysParams.scriptReferences.iAssetTokenPolicyRef,
|
|
737
|
+
),
|
|
738
|
+
]),
|
|
739
|
+
(_) => new Error('Expected a single iasset token policy Ref Script UTXO'),
|
|
740
|
+
);
|
|
741
|
+
|
|
742
|
+
const cdpUtxo = matchSingle(
|
|
743
|
+
await lucid.utxosByOutRef([cdpOref]),
|
|
744
|
+
(_) => new Error('Expected a single cdp UTXO'),
|
|
745
|
+
);
|
|
746
|
+
const cdpDatum = parseCdpDatumOrThrow(getInlineDatumOrThrow(cdpUtxo));
|
|
747
|
+
|
|
748
|
+
const iassetUtxo = matchSingle(
|
|
749
|
+
await lucid.utxosByOutRef([iassetOref]),
|
|
750
|
+
(_) => new Error('Expected a single iasset UTXO'),
|
|
751
|
+
);
|
|
752
|
+
const iassetDatum = parseIAssetDatumOrThrow(
|
|
753
|
+
getInlineDatumOrThrow(iassetUtxo),
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
const priceOracleUtxo = matchSingle(
|
|
757
|
+
await lucid.utxosByOutRef([priceOracleOref]),
|
|
758
|
+
(_) => new Error('Expected a single price oracle UTXO'),
|
|
759
|
+
);
|
|
760
|
+
const priceOracleDatum = parsePriceOracleDatum(
|
|
761
|
+
getInlineDatumOrThrow(priceOracleUtxo),
|
|
762
|
+
);
|
|
763
|
+
|
|
764
|
+
const interestOracleUtxo = matchSingle(
|
|
765
|
+
await lucid.utxosByOutRef([interestOracleOref]),
|
|
766
|
+
(_) => new Error('Expected a single interest oracle UTXO'),
|
|
767
|
+
);
|
|
768
|
+
const interestOracleDatum = parseInterestOracleDatum(
|
|
769
|
+
getInlineDatumOrThrow(interestOracleUtxo),
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
const interestAdaAmt = match(cdpDatum.cdpFees)
|
|
773
|
+
.with({ FrozenCDPAccumulatedFees: P.any }, () => {
|
|
774
|
+
throw new Error('CDP fees wrong');
|
|
775
|
+
})
|
|
776
|
+
.with({ ActiveCDPInterestTracking: P.select() }, (interest) => {
|
|
777
|
+
const interestPaymentIAssetAmt = calculateAccruedInterest(
|
|
778
|
+
currentTime,
|
|
779
|
+
interest.unitaryInterestSnapshot,
|
|
780
|
+
cdpDatum.mintedAmt,
|
|
781
|
+
interest.lastSettled,
|
|
782
|
+
interestOracleDatum,
|
|
783
|
+
);
|
|
784
|
+
|
|
785
|
+
return ocdMul(
|
|
786
|
+
{ getOnChainInt: interestPaymentIAssetAmt },
|
|
787
|
+
priceOracleDatum.price,
|
|
788
|
+
).getOnChainInt;
|
|
789
|
+
})
|
|
790
|
+
.exhaustive();
|
|
791
|
+
|
|
792
|
+
const interestCollectorAdaAmt = calculateFeeFromPercentage(
|
|
793
|
+
iassetDatum.interestCollectorPortionPercentage,
|
|
794
|
+
interestAdaAmt,
|
|
795
|
+
);
|
|
796
|
+
const interestTreasuryAdaAmt = interestAdaAmt - interestCollectorAdaAmt;
|
|
797
|
+
|
|
798
|
+
const collateralAmtMinusInterest =
|
|
799
|
+
lovelacesAmt(cdpUtxo.assets) - interestAdaAmt;
|
|
800
|
+
|
|
801
|
+
const [isPartial, redemptionIAssetAmt] = (() => {
|
|
802
|
+
const res = calculateMinCollateralCappedIAssetRedemptionAmt(
|
|
803
|
+
collateralAmtMinusInterest,
|
|
804
|
+
cdpDatum.mintedAmt,
|
|
805
|
+
priceOracleDatum.price,
|
|
806
|
+
iassetDatum.redemptionRatio,
|
|
807
|
+
iassetDatum.redemptionReimbursementPercentage,
|
|
808
|
+
BigInt(sysParams.cdpParams.minCollateralInLovelace),
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
const redemptionAmt = bigintMin(
|
|
812
|
+
attemptedRedemptionIAssetAmt,
|
|
813
|
+
res.cappedIAssetRedemptionAmt,
|
|
814
|
+
);
|
|
815
|
+
|
|
816
|
+
return [redemptionAmt < res.cappedIAssetRedemptionAmt, redemptionAmt];
|
|
817
|
+
})();
|
|
818
|
+
|
|
819
|
+
if (redemptionIAssetAmt <= 0) {
|
|
820
|
+
throw new Error("There's no iAssets available for redemption.");
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
const redemptionLovelacesAmt = ocdMul(priceOracleDatum.price, {
|
|
824
|
+
getOnChainInt: redemptionIAssetAmt,
|
|
825
|
+
}).getOnChainInt;
|
|
826
|
+
|
|
827
|
+
const partialRedemptionFee = isPartial
|
|
828
|
+
? BigInt(sysParams.cdpParams.partialRedemptionExtraFeeLovelace)
|
|
829
|
+
: 0n;
|
|
830
|
+
|
|
831
|
+
const processingFee = calculateFeeFromPercentage(
|
|
832
|
+
iassetDatum.redemptionProcessingFeePercentage,
|
|
833
|
+
redemptionLovelacesAmt,
|
|
834
|
+
);
|
|
835
|
+
|
|
836
|
+
const reimburstmentFee = calculateFeeFromPercentage(
|
|
837
|
+
iassetDatum.redemptionReimbursementPercentage,
|
|
838
|
+
redemptionLovelacesAmt,
|
|
839
|
+
);
|
|
840
|
+
|
|
841
|
+
const txValidity = oracleExpirationAwareValidity(
|
|
842
|
+
currentSlot,
|
|
843
|
+
Number(sysParams.cdpCreatorParams.biasTime),
|
|
844
|
+
Number(priceOracleDatum.expiration),
|
|
845
|
+
network,
|
|
846
|
+
);
|
|
847
|
+
|
|
848
|
+
const tx = lucid
|
|
849
|
+
.newTx()
|
|
850
|
+
// Ref Script
|
|
851
|
+
.readFrom([cdpRefScriptUtxo, iAssetTokenPolicyRefScriptUtxo])
|
|
852
|
+
// Ref inputs
|
|
853
|
+
.readFrom([iassetUtxo, priceOracleUtxo, interestOracleUtxo])
|
|
854
|
+
.validFrom(txValidity.validFrom)
|
|
855
|
+
.validTo(txValidity.validTo)
|
|
856
|
+
.collectFrom(
|
|
857
|
+
[cdpUtxo],
|
|
858
|
+
serialiseCdpRedeemer({ RedeemCdp: { currentTime: currentTime } }),
|
|
859
|
+
)
|
|
860
|
+
.mintAssets(
|
|
861
|
+
mkAssetsOf(
|
|
862
|
+
{
|
|
863
|
+
currencySymbol: sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
|
|
864
|
+
tokenName: iassetDatum.assetName,
|
|
865
|
+
},
|
|
866
|
+
-redemptionIAssetAmt,
|
|
867
|
+
),
|
|
868
|
+
Data.void(),
|
|
869
|
+
)
|
|
870
|
+
.pay.ToContract(
|
|
871
|
+
cdpUtxo.address,
|
|
872
|
+
{
|
|
873
|
+
kind: 'inline',
|
|
874
|
+
value: serialiseCdpDatum({
|
|
875
|
+
...cdpDatum,
|
|
876
|
+
mintedAmt: cdpDatum.mintedAmt - redemptionIAssetAmt,
|
|
877
|
+
cdpFees: {
|
|
878
|
+
ActiveCDPInterestTracking: {
|
|
879
|
+
lastSettled: currentTime,
|
|
880
|
+
unitaryInterestSnapshot:
|
|
881
|
+
interestOracleDatum.unitaryInterest +
|
|
882
|
+
calculateUnitaryInterestSinceOracleLastUpdated(
|
|
883
|
+
currentTime,
|
|
884
|
+
interestOracleDatum,
|
|
885
|
+
),
|
|
886
|
+
},
|
|
887
|
+
},
|
|
888
|
+
}),
|
|
889
|
+
},
|
|
890
|
+
addAssets(
|
|
891
|
+
cdpUtxo.assets,
|
|
892
|
+
mkLovelacesOf(-redemptionLovelacesAmt),
|
|
893
|
+
mkLovelacesOf(reimburstmentFee),
|
|
894
|
+
mkLovelacesOf(-interestAdaAmt),
|
|
895
|
+
),
|
|
896
|
+
);
|
|
897
|
+
|
|
898
|
+
await collectorFeeTx(
|
|
899
|
+
processingFee + partialRedemptionFee + interestCollectorAdaAmt,
|
|
900
|
+
lucid,
|
|
901
|
+
sysParams,
|
|
902
|
+
tx,
|
|
903
|
+
collectorOref,
|
|
904
|
+
);
|
|
905
|
+
|
|
906
|
+
await treasuryFeeTx(
|
|
907
|
+
interestTreasuryAdaAmt,
|
|
908
|
+
lucid,
|
|
909
|
+
sysParams,
|
|
910
|
+
tx,
|
|
911
|
+
treasuryOref,
|
|
912
|
+
);
|
|
913
|
+
|
|
914
|
+
return tx;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
export async function freezeCdp(
|
|
918
|
+
cdpOref: OutRef,
|
|
919
|
+
iassetOref: OutRef,
|
|
920
|
+
priceOracleOref: OutRef,
|
|
921
|
+
interestOracleOref: OutRef,
|
|
922
|
+
sysParams: SystemParams,
|
|
923
|
+
lucid: LucidEvolution,
|
|
924
|
+
currentSlot: number,
|
|
925
|
+
): Promise<TxBuilder> {
|
|
926
|
+
const network = lucid.config().network!;
|
|
927
|
+
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
|
|
928
|
+
|
|
929
|
+
const cdpRefScriptUtxo = matchSingle(
|
|
930
|
+
await lucid.utxosByOutRef([
|
|
931
|
+
fromSystemParamsScriptRef(sysParams.scriptReferences.cdpValidatorRef),
|
|
932
|
+
]),
|
|
933
|
+
(_) => new Error('Expected a single cdp Ref Script UTXO'),
|
|
934
|
+
);
|
|
935
|
+
const cdpUtxo = matchSingle(
|
|
936
|
+
await lucid.utxosByOutRef([cdpOref]),
|
|
937
|
+
(_) => new Error('Expected a single cdp UTXO'),
|
|
938
|
+
);
|
|
939
|
+
const cdpDatum = parseCdpDatumOrThrow(getInlineDatumOrThrow(cdpUtxo));
|
|
940
|
+
|
|
941
|
+
const iassetUtxo = matchSingle(
|
|
942
|
+
await lucid.utxosByOutRef([iassetOref]),
|
|
943
|
+
(_) => new Error('Expected a single iasset UTXO'),
|
|
944
|
+
);
|
|
945
|
+
const iassetDatum = parseIAssetDatumOrThrow(
|
|
946
|
+
getInlineDatumOrThrow(iassetUtxo),
|
|
947
|
+
);
|
|
948
|
+
|
|
949
|
+
const priceOracleUtxo = matchSingle(
|
|
950
|
+
await lucid.utxosByOutRef([priceOracleOref]),
|
|
951
|
+
(_) => new Error('Expected a single price oracle UTXO'),
|
|
952
|
+
);
|
|
953
|
+
const priceOracleDatum = parsePriceOracleDatum(
|
|
954
|
+
getInlineDatumOrThrow(priceOracleUtxo),
|
|
955
|
+
);
|
|
956
|
+
|
|
957
|
+
const interestOracleUtxo = matchSingle(
|
|
958
|
+
await lucid.utxosByOutRef([interestOracleOref]),
|
|
959
|
+
(_) => new Error('Expected a single interest oracle UTXO'),
|
|
960
|
+
);
|
|
961
|
+
const interestOracleDatum = parseInterestOracleDatum(
|
|
962
|
+
getInlineDatumOrThrow(interestOracleUtxo),
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
const interestAdaAmt = match(cdpDatum.cdpFees)
|
|
966
|
+
.with({ FrozenCDPAccumulatedFees: P.any }, () => {
|
|
967
|
+
throw new Error('CDP fees wrong');
|
|
968
|
+
})
|
|
969
|
+
.with({ ActiveCDPInterestTracking: P.select() }, (interest) => {
|
|
970
|
+
const interestPaymentIAssetAmt = calculateAccruedInterest(
|
|
971
|
+
currentTime,
|
|
972
|
+
interest.unitaryInterestSnapshot,
|
|
973
|
+
cdpDatum.mintedAmt,
|
|
974
|
+
interest.lastSettled,
|
|
975
|
+
interestOracleDatum,
|
|
976
|
+
);
|
|
977
|
+
|
|
978
|
+
const maxInterestLovelaces = computeInterestLovelacesFor100PercentCR(
|
|
979
|
+
lovelacesAmt(cdpUtxo.assets),
|
|
980
|
+
cdpDatum.mintedAmt,
|
|
981
|
+
priceOracleDatum.price,
|
|
982
|
+
);
|
|
983
|
+
|
|
984
|
+
return bigintMin(
|
|
985
|
+
maxInterestLovelaces,
|
|
986
|
+
ocdMul(
|
|
987
|
+
{ getOnChainInt: interestPaymentIAssetAmt },
|
|
988
|
+
priceOracleDatum.price,
|
|
989
|
+
).getOnChainInt,
|
|
990
|
+
);
|
|
991
|
+
})
|
|
992
|
+
.exhaustive();
|
|
993
|
+
|
|
994
|
+
const interestCollectorAdaAmt = calculateFeeFromPercentage(
|
|
995
|
+
iassetDatum.interestCollectorPortionPercentage,
|
|
996
|
+
interestAdaAmt,
|
|
997
|
+
);
|
|
998
|
+
|
|
999
|
+
const interestTreasuryAdaAmt = interestAdaAmt - interestCollectorAdaAmt;
|
|
1000
|
+
|
|
1001
|
+
const inputCollateralMinusInterest =
|
|
1002
|
+
lovelacesAmt(cdpUtxo.assets) - interestAdaAmt;
|
|
1003
|
+
|
|
1004
|
+
const cdpDebtAdaValue = ocdMul(
|
|
1005
|
+
{ getOnChainInt: cdpDatum.mintedAmt },
|
|
1006
|
+
priceOracleDatum.price,
|
|
1007
|
+
).getOnChainInt;
|
|
1008
|
+
|
|
1009
|
+
const liquidationProcessingFee = bigintMin(
|
|
1010
|
+
calculateFeeFromPercentage(
|
|
1011
|
+
iassetDatum.liquidationProcessingFeePercentage,
|
|
1012
|
+
inputCollateralMinusInterest,
|
|
1013
|
+
),
|
|
1014
|
+
calculateFeeFromPercentage(
|
|
1015
|
+
iassetDatum.liquidationProcessingFeePercentage,
|
|
1016
|
+
cdpDebtAdaValue,
|
|
1017
|
+
),
|
|
1018
|
+
);
|
|
1019
|
+
|
|
1020
|
+
const txValidity = oracleExpirationAwareValidity(
|
|
1021
|
+
currentSlot,
|
|
1022
|
+
Number(sysParams.cdpCreatorParams.biasTime),
|
|
1023
|
+
Number(priceOracleDatum.expiration),
|
|
1024
|
+
network,
|
|
1025
|
+
);
|
|
1026
|
+
|
|
1027
|
+
return (
|
|
1028
|
+
lucid
|
|
1029
|
+
.newTx()
|
|
1030
|
+
// Ref Script
|
|
1031
|
+
.readFrom([cdpRefScriptUtxo])
|
|
1032
|
+
// Ref inputs
|
|
1033
|
+
.readFrom([iassetUtxo, priceOracleUtxo, interestOracleUtxo])
|
|
1034
|
+
.validFrom(txValidity.validFrom)
|
|
1035
|
+
.validTo(txValidity.validTo)
|
|
1036
|
+
.collectFrom(
|
|
1037
|
+
[cdpUtxo],
|
|
1038
|
+
serialiseCdpRedeemer({ FreezeCdp: { currentTime: currentTime } }),
|
|
1039
|
+
)
|
|
1040
|
+
.pay.ToContract(
|
|
1041
|
+
createScriptAddress(network, sysParams.validatorHashes.cdpHash),
|
|
1042
|
+
{
|
|
1043
|
+
kind: 'inline',
|
|
1044
|
+
value: serialiseCdpDatum({
|
|
1045
|
+
...cdpDatum,
|
|
1046
|
+
cdpOwner: null,
|
|
1047
|
+
cdpFees: {
|
|
1048
|
+
FrozenCDPAccumulatedFees: {
|
|
1049
|
+
lovelacesIndyStakers:
|
|
1050
|
+
liquidationProcessingFee + interestCollectorAdaAmt,
|
|
1051
|
+
lovelacesTreasury: interestTreasuryAdaAmt,
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
}),
|
|
1055
|
+
},
|
|
1056
|
+
cdpUtxo.assets,
|
|
1057
|
+
)
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
export async function liquidateCdp(
|
|
1062
|
+
cdpOref: OutRef,
|
|
1063
|
+
stabilityPoolOref: OutRef,
|
|
1064
|
+
collectorOref: OutRef,
|
|
1065
|
+
treasuryOref: OutRef,
|
|
1066
|
+
sysParams: SystemParams,
|
|
1067
|
+
lucid: LucidEvolution,
|
|
1068
|
+
): Promise<TxBuilder> {
|
|
1069
|
+
const cdpRefScriptUtxo = matchSingle(
|
|
1070
|
+
await lucid.utxosByOutRef([
|
|
1071
|
+
fromSystemParamsScriptRef(sysParams.scriptReferences.cdpValidatorRef),
|
|
1072
|
+
]),
|
|
1073
|
+
(_) => new Error('Expected a single cdp Ref Script UTXO'),
|
|
1074
|
+
);
|
|
1075
|
+
const stabilityPoolRefScriptUtxo = matchSingle(
|
|
1076
|
+
await lucid.utxosByOutRef([
|
|
1077
|
+
fromSystemParamsScriptRef(
|
|
1078
|
+
sysParams.scriptReferences.stabilityPoolValidatorRef,
|
|
1079
|
+
),
|
|
1080
|
+
]),
|
|
1081
|
+
(_) => new Error('Expected a single stability pool Ref Script UTXO'),
|
|
1082
|
+
);
|
|
1083
|
+
const iAssetTokenPolicyRefScriptUtxo = matchSingle(
|
|
1084
|
+
await lucid.utxosByOutRef([
|
|
1085
|
+
fromSystemParamsScriptRef(
|
|
1086
|
+
sysParams.scriptReferences.iAssetTokenPolicyRef,
|
|
1087
|
+
),
|
|
1088
|
+
]),
|
|
1089
|
+
(_) => new Error('Expected a single iasset token policy Ref Script UTXO'),
|
|
1090
|
+
);
|
|
1091
|
+
const cdpAuthTokenPolicyRefScriptUtxo = matchSingle(
|
|
1092
|
+
await lucid.utxosByOutRef([
|
|
1093
|
+
fromSystemParamsScriptRef(
|
|
1094
|
+
sysParams.scriptReferences.authTokenPolicies.cdpAuthTokenRef,
|
|
1095
|
+
),
|
|
1096
|
+
]),
|
|
1097
|
+
(_) => new Error('Expected a single cdp auth token policy Ref Script UTXO'),
|
|
1098
|
+
);
|
|
1099
|
+
|
|
1100
|
+
const cdpUtxo = matchSingle(
|
|
1101
|
+
await lucid.utxosByOutRef([cdpOref]),
|
|
1102
|
+
(_) => new Error('Expected a single cdp UTXO'),
|
|
1103
|
+
);
|
|
1104
|
+
const cdpDatum = parseCdpDatumOrThrow(getInlineDatumOrThrow(cdpUtxo));
|
|
1105
|
+
|
|
1106
|
+
const spUtxo = matchSingle(
|
|
1107
|
+
await lucid.utxosByOutRef([stabilityPoolOref]),
|
|
1108
|
+
(_) => new Error('Expected a single stability pool UTXO'),
|
|
1109
|
+
);
|
|
1110
|
+
const spDatum = parseStabilityPoolDatum(getInlineDatumOrThrow(spUtxo));
|
|
1111
|
+
|
|
1112
|
+
const [lovelacesForTreasury, lovelacesForCollector] = match(cdpDatum.cdpFees)
|
|
1113
|
+
.returnType<[bigint, bigint]>()
|
|
1114
|
+
.with({ FrozenCDPAccumulatedFees: P.select() }, (fees) => [
|
|
1115
|
+
fees.lovelacesTreasury,
|
|
1116
|
+
fees.lovelacesIndyStakers,
|
|
1117
|
+
])
|
|
1118
|
+
.with({ ActiveCDPInterestTracking: P.any }, () => {
|
|
1119
|
+
throw new Error('CDP fees wrong');
|
|
1120
|
+
})
|
|
1121
|
+
.exhaustive();
|
|
1122
|
+
|
|
1123
|
+
const cdpNftAc = fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken);
|
|
1124
|
+
const iassetsAc = {
|
|
1125
|
+
currencySymbol: sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
|
|
1126
|
+
tokenName: cdpDatum.iasset,
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
const spIassetAmt = assetClassValueOf(spUtxo.assets, iassetsAc);
|
|
1130
|
+
|
|
1131
|
+
const iassetBurnAmt = bigintMin(cdpDatum.mintedAmt, spIassetAmt);
|
|
1132
|
+
|
|
1133
|
+
const collateralAvailable = lovelacesAmt(cdpUtxo.assets);
|
|
1134
|
+
const collateralAvailMinusFees =
|
|
1135
|
+
collateralAvailable - lovelacesForCollector - lovelacesForTreasury;
|
|
1136
|
+
const collateralAbsorbed =
|
|
1137
|
+
(collateralAvailMinusFees * iassetBurnAmt) / cdpDatum.mintedAmt;
|
|
1138
|
+
|
|
1139
|
+
const isPartial = spIassetAmt < cdpDatum.mintedAmt;
|
|
1140
|
+
|
|
1141
|
+
const tx = lucid
|
|
1142
|
+
.newTx()
|
|
1143
|
+
.readFrom([
|
|
1144
|
+
cdpRefScriptUtxo,
|
|
1145
|
+
stabilityPoolRefScriptUtxo,
|
|
1146
|
+
iAssetTokenPolicyRefScriptUtxo,
|
|
1147
|
+
cdpAuthTokenPolicyRefScriptUtxo,
|
|
1148
|
+
])
|
|
1149
|
+
.collectFrom([spUtxo], serialiseStabilityPoolRedeemer('LiquidateCDP'))
|
|
1150
|
+
.collectFrom([cdpUtxo], serialiseCdpRedeemer('Liquidate'))
|
|
1151
|
+
.mintAssets(mkAssetsOf(iassetsAc, -iassetBurnAmt), Data.void())
|
|
1152
|
+
.pay.ToContract(
|
|
1153
|
+
spUtxo.address,
|
|
1154
|
+
{
|
|
1155
|
+
kind: 'inline',
|
|
1156
|
+
value: serialiseStabilityPoolDatum({
|
|
1157
|
+
StabilityPool: liquidationHelper(
|
|
1158
|
+
spDatum,
|
|
1159
|
+
iassetBurnAmt,
|
|
1160
|
+
collateralAbsorbed,
|
|
1161
|
+
).newSpContent,
|
|
1162
|
+
}),
|
|
1163
|
+
},
|
|
1164
|
+
addAssets(
|
|
1165
|
+
spUtxo.assets,
|
|
1166
|
+
mkLovelacesOf(collateralAbsorbed),
|
|
1167
|
+
mkAssetsOf(iassetsAc, -iassetBurnAmt),
|
|
1168
|
+
),
|
|
1169
|
+
);
|
|
1170
|
+
|
|
1171
|
+
if (isPartial) {
|
|
1172
|
+
tx.pay.ToContract(
|
|
1173
|
+
cdpUtxo.address,
|
|
1174
|
+
{
|
|
1175
|
+
kind: 'inline',
|
|
1176
|
+
value: serialiseCdpDatum({
|
|
1177
|
+
...cdpDatum,
|
|
1178
|
+
mintedAmt: cdpDatum.mintedAmt - spIassetAmt,
|
|
1179
|
+
cdpFees: {
|
|
1180
|
+
FrozenCDPAccumulatedFees: {
|
|
1181
|
+
lovelacesIndyStakers: 0n,
|
|
1182
|
+
lovelacesTreasury: 0n,
|
|
1183
|
+
},
|
|
1184
|
+
},
|
|
1185
|
+
}),
|
|
1186
|
+
},
|
|
1187
|
+
addAssets(
|
|
1188
|
+
mkAssetsOf(cdpNftAc, assetClassValueOf(cdpUtxo.assets, cdpNftAc)),
|
|
1189
|
+
mkLovelacesOf(collateralAvailable - collateralAbsorbed),
|
|
1190
|
+
),
|
|
1191
|
+
);
|
|
1192
|
+
} else {
|
|
1193
|
+
tx.mintAssets(
|
|
1194
|
+
mkAssetsOf(cdpNftAc, -assetClassValueOf(cdpUtxo.assets, cdpNftAc)),
|
|
1195
|
+
Data.void(),
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
await collectorFeeTx(
|
|
1200
|
+
lovelacesForCollector,
|
|
1201
|
+
lucid,
|
|
1202
|
+
sysParams,
|
|
1203
|
+
tx,
|
|
1204
|
+
collectorOref,
|
|
1205
|
+
);
|
|
1206
|
+
|
|
1207
|
+
await treasuryFeeTx(lovelacesForTreasury, lucid, sysParams, tx, treasuryOref);
|
|
1208
|
+
|
|
1209
|
+
return tx;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
export async function mergeCdps(
|
|
1213
|
+
cdpsToMergeUtxos: OutRef[],
|
|
1214
|
+
sysParams: SystemParams,
|
|
1215
|
+
lucid: LucidEvolution,
|
|
1216
|
+
): Promise<TxBuilder> {
|
|
1217
|
+
const cdpRefScriptUtxo = matchSingle(
|
|
1218
|
+
await lucid.utxosByOutRef([
|
|
1219
|
+
fromSystemParamsScriptRef(sysParams.scriptReferences.cdpValidatorRef),
|
|
1220
|
+
]),
|
|
1221
|
+
(_) => new Error('Expected a single cdp Ref Script UTXO'),
|
|
1222
|
+
);
|
|
1223
|
+
|
|
1224
|
+
const cdpUtxos = await lucid.utxosByOutRef(cdpsToMergeUtxos);
|
|
1225
|
+
const cdpDatums = cdpUtxos.map((utxo) =>
|
|
1226
|
+
parseCdpDatumOrThrow(getInlineDatumOrThrow(utxo)),
|
|
1227
|
+
);
|
|
1228
|
+
|
|
1229
|
+
if (cdpUtxos.length !== cdpsToMergeUtxos.length) {
|
|
1230
|
+
throw new Error('Expected certain number of CDPs');
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
const aggregatedVal = F.pipe(
|
|
1234
|
+
cdpUtxos,
|
|
1235
|
+
A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets)),
|
|
1236
|
+
);
|
|
1237
|
+
|
|
1238
|
+
const aggregatedMintedAmt = F.pipe(
|
|
1239
|
+
cdpDatums,
|
|
1240
|
+
A.reduce<CDPContent, bigint>(0n, (acc, cdpDat) => acc + cdpDat.mintedAmt),
|
|
1241
|
+
);
|
|
1242
|
+
|
|
1243
|
+
type AggregatedFees = {
|
|
1244
|
+
aggregatedFeeIndyStakers: bigint;
|
|
1245
|
+
aggregatedFeeTreasury: bigint;
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
const { aggregatedFeeTreasury, aggregatedFeeIndyStakers } = F.pipe(
|
|
1249
|
+
cdpDatums,
|
|
1250
|
+
A.reduce<CDPContent, AggregatedFees>(
|
|
1251
|
+
{ aggregatedFeeIndyStakers: 0n, aggregatedFeeTreasury: 0n },
|
|
1252
|
+
(acc, cdpDat) =>
|
|
1253
|
+
match(cdpDat.cdpFees)
|
|
1254
|
+
.returnType<AggregatedFees>()
|
|
1255
|
+
.with({ FrozenCDPAccumulatedFees: P.select() }, (fees) => ({
|
|
1256
|
+
aggregatedFeeIndyStakers:
|
|
1257
|
+
acc.aggregatedFeeIndyStakers + fees.lovelacesIndyStakers,
|
|
1258
|
+
aggregatedFeeTreasury:
|
|
1259
|
+
acc.aggregatedFeeTreasury + fees.lovelacesTreasury,
|
|
1260
|
+
}))
|
|
1261
|
+
.otherwise(() => acc),
|
|
1262
|
+
),
|
|
1263
|
+
);
|
|
1264
|
+
|
|
1265
|
+
const [[mainMergeUtxo, mainCdpDatum], otherMergeUtxos] = match(
|
|
1266
|
+
A.zip(cdpUtxos, cdpDatums),
|
|
1267
|
+
)
|
|
1268
|
+
.returnType<[[UTxO, CDPContent], UTxO[]]>()
|
|
1269
|
+
.with([P._, ...P.array()], ([main, ...other]) => [
|
|
1270
|
+
main,
|
|
1271
|
+
other.map((a) => a[0]),
|
|
1272
|
+
])
|
|
1273
|
+
.otherwise(() => {
|
|
1274
|
+
throw new Error('Expects more CDPs for merging');
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
return lucid
|
|
1278
|
+
.newTx()
|
|
1279
|
+
.readFrom([cdpRefScriptUtxo])
|
|
1280
|
+
.collectFrom([mainMergeUtxo], serialiseCdpRedeemer('MergeCdps'))
|
|
1281
|
+
.collectFrom(
|
|
1282
|
+
otherMergeUtxos,
|
|
1283
|
+
serialiseCdpRedeemer({
|
|
1284
|
+
MergeAuxiliary: {
|
|
1285
|
+
mainMergeUtxo: {
|
|
1286
|
+
outputIndex: BigInt(mainMergeUtxo.outputIndex),
|
|
1287
|
+
txHash: { hash: mainMergeUtxo.txHash },
|
|
1288
|
+
},
|
|
1289
|
+
},
|
|
1290
|
+
}),
|
|
1291
|
+
)
|
|
1292
|
+
.pay.ToContract(
|
|
1293
|
+
mainMergeUtxo.address,
|
|
1294
|
+
{
|
|
1295
|
+
kind: 'inline',
|
|
1296
|
+
value: serialiseCdpDatum({
|
|
1297
|
+
cdpOwner: null,
|
|
1298
|
+
iasset: mainCdpDatum.iasset,
|
|
1299
|
+
mintedAmt: aggregatedMintedAmt,
|
|
1300
|
+
cdpFees: {
|
|
1301
|
+
FrozenCDPAccumulatedFees: {
|
|
1302
|
+
lovelacesIndyStakers: aggregatedFeeIndyStakers,
|
|
1303
|
+
lovelacesTreasury: aggregatedFeeTreasury,
|
|
1304
|
+
},
|
|
1305
|
+
},
|
|
1306
|
+
}),
|
|
1307
|
+
},
|
|
1308
|
+
aggregatedVal,
|
|
1309
|
+
);
|
|
1310
|
+
}
|