@indigo-labs/indigo-sdk
Version:
Indigo SDK for interacting with Indigo endpoints via lucid-evolution
856 lines (760 loc) • 23.9 kB
text/typescript
import {
addAssets,
Data,
fromHex,
getInputIndices,
LucidEvolution,
OutRef,
slotToUnixTime,
toHex,
TxBuilder,
} from '@lucid-evolution/lucid';
import {
addrDetails,
buildRedemptionsTx,
collectInterestTx,
createScriptAddress,
fromSystemParamsAsset,
fromSystemParamsScriptRef,
getInlineDatumOrThrow,
matchSingle,
SystemParams,
treasuryFeeTx,
} from '../../src';
import {
parseCollateralAssetDatumOrThrow,
parseIAssetDatumOrThrow,
} from '../../src/contracts/iasset/types';
import { match, P } from 'ts-pattern';
import { parsePriceOracleDatum } from '../../src/contracts/price-oracle/types-new';
import { unzip, zip } from 'fp-ts/lib/Array';
import {
parseCdpDatumOrThrow,
serialiseCdpDatum,
serialiseCdpRedeemer,
} from '../../src/contracts/cdp/types-new';
import { parseInterestOracleDatum } from '../../src/contracts/interest-oracle/types-new';
import {
calculateAccruedInterest,
calculateUnitaryInterestSinceOracleLastUpdated,
} from '../../src/contracts/interest-oracle/helpers';
import { mkAssetsOf } from '@3rd-eye-labs/cardano-offchain-common';
import { oracleExpirationAwareValidity } from '../../src/contracts/price-oracle/helpers';
import { calculateFeeFromRatio } from '../../src/utils/indigo-helpers';
import {
serialiseCDPCreatorDatum,
serialiseCDPCreatorRedeemer,
} from '../../src/contracts/cdp-creator/types-new';
import { retrieveAdjustedPrice } from '../../src/utils/oracle-helpers';
// Unlike the real redeemRob function, this one allows building a transaction to redeem
// using a delisted iAsset. Therefore, no price oracle is required.
export async function testRedeemRob(
redemptionRobsData: [OutRef, bigint][],
priceOracleOutRef: OutRef | undefined,
iassetOutRef: OutRef,
collateralAssetOutRef: OutRef,
lucid: LucidEvolution,
currentSlot: number,
sysParams: SystemParams,
pythMessage?: string,
): Promise<TxBuilder> {
const network = lucid.config().network!;
const robScriptRefUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(sysParams.scriptReferences.robValidatorRef),
]),
(_) => new Error('Expected a single ROB Ref Script UTXO'),
);
const iassetUtxo = matchSingle(
await lucid.utxosByOutRef([iassetOutRef]),
(_) => new Error('Expected a single IAsset UTXO'),
);
const iassetDatum = parseIAssetDatumOrThrow(
getInlineDatumOrThrow(iassetUtxo),
);
const collateralAssetUtxo = matchSingle(
await lucid.utxosByOutRef([collateralAssetOutRef]),
(_) => new Error('Expected a single collateral asset UTXO'),
);
const collateralAssetDatum = parseCollateralAssetDatumOrThrow(
getInlineDatumOrThrow(collateralAssetUtxo),
);
const [adjustedPrice, priceOracleUtxo] = await retrieveAdjustedPrice(
iassetDatum.assetName,
collateralAssetDatum.collateralAsset,
collateralAssetDatum.priceInfo,
collateralAssetDatum.extraDecimals,
priceOracleOutRef,
pythMessage,
sysParams.pythConfig,
lucid,
);
const [robsToRedeemOutRefs, robRedemptionIAssetAmt] =
unzip(redemptionRobsData);
const redemptionRobs = await lucid
.utxosByOutRef(robsToRedeemOutRefs)
.then((val) => zip(val, robRedemptionIAssetAmt));
const allRefInputs = [
robScriptRefUtxo,
iassetUtxo,
collateralAssetUtxo,
...(priceOracleUtxo == null ? [] : [priceOracleUtxo]),
];
const refInputIdxs = getInputIndices(allRefInputs, allRefInputs);
const tx = buildRedemptionsTx(
redemptionRobs,
iassetDatum.assetName,
collateralAssetDatum.collateralAsset,
adjustedPrice,
iassetDatum.redemptionReimbursementRatio,
sysParams,
lucid.newTx(),
0n,
refInputIdxs[2],
refInputIdxs[1],
priceOracleOutRef !== undefined
? { OracleRefInputIdx: refInputIdxs[3] }
: 'OracleVoid',
);
const transaction = lucid
.newTx()
.validTo(slotToUnixTime(network, currentSlot))
.readFrom(allRefInputs)
.compose(tx);
if (priceOracleUtxo != null) {
transaction.readFrom([priceOracleUtxo]);
}
return transaction;
}
export async function redeemWithCdpCreate(
redemptionRobsData: [OutRef, bigint][],
collateralAmount: bigint,
mintedAmount: bigint,
sysParams: SystemParams,
cdpCreatorOref: OutRef,
iassetOref: OutRef,
collateralAssetOref: OutRef,
priceOracleOref: OutRef,
interestOracleOref: OutRef,
treasuryOref: OutRef,
lucid: LucidEvolution,
currentSlot: number,
): Promise<TxBuilder> {
const network = lucid.config().network!;
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
const [pkh, skh] = await addrDetails(lucid);
const treasuryRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.treasuryValidatorRef,
),
]),
(_) => new Error('Expected a single treasury Ref Script UTXO'),
);
const robScriptRefUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(sysParams.scriptReferences.robValidatorRef),
]),
(_) => new Error('Expected a single ROB Ref Script UTXO'),
);
const cdpCreatorRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.cdpCreatorValidatorRef,
),
]),
(_) => new Error('Expected a single cdp creator Ref Script UTXO'),
);
const cdpAuthTokenPolicyRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.authTokenPolicies.cdpAuthTokenRef,
),
]),
(_) => new Error('Expected a single cdp auth token policy Ref Script UTXO'),
);
const iAssetTokenPolicyRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.iAssetTokenPolicyRef,
),
]),
(_) => new Error('Expected a single iasset token policy Ref Script UTXO'),
);
const iassetUtxo = matchSingle(
await lucid.utxosByOutRef([iassetOref]),
(_) => new Error('Expected a single iasset UTXO'),
);
const iassetDatum = parseIAssetDatumOrThrow(
getInlineDatumOrThrow(iassetUtxo),
);
const collateralAssetUtxo = matchSingle(
await lucid.utxosByOutRef([collateralAssetOref]),
(_) => new Error('Expected a single collateral asset UTXO'),
);
const collateralAssetDatum = parseCollateralAssetDatumOrThrow(
getInlineDatumOrThrow(collateralAssetUtxo),
);
const priceOracleUtxo = matchSingle(
await lucid.utxosByOutRef([priceOracleOref]),
(_) => new Error('Expected a single price oracle UTXO'),
);
const priceOracleDatum = parsePriceOracleDatum(
getInlineDatumOrThrow(priceOracleUtxo),
);
const interestOracleUtxo = matchSingle(
await lucid.utxosByOutRef([interestOracleOref]),
(_) => new Error('Expected a single interest oracle UTXO'),
);
const interestOracleDatum = parseInterestOracleDatum(
getInlineDatumOrThrow(interestOracleUtxo),
);
const cdpCreatorUtxo = matchSingle(
await lucid.utxosByOutRef([cdpCreatorOref]),
(_) => new Error('Expected a single CDP creator UTXO'),
);
match(collateralAssetDatum.priceInfo)
.with({ Delisted: P.any }, () => {
throw new Error("Can't open CDP of delisted asset");
})
.otherwise(() => {});
const cdpNftVal = mkAssetsOf(
fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken),
1n,
);
const iassetClass = {
currencySymbol: fromHex(
sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
),
tokenName: iassetDatum.assetName,
};
const debtMintingFee = calculateFeeFromRatio(
iassetDatum.debtMintingFeeRatio,
mintedAmount,
);
const iassetTokensVal = mkAssetsOf(iassetClass, mintedAmount);
const [robsToRedeemOutRefs, robRedemptionIAssetAmt] =
unzip(redemptionRobsData);
const redemptionRobs = await lucid
.utxosByOutRef(robsToRedeemOutRefs)
.then((val) => zip(val, robRedemptionIAssetAmt));
const allRefInputs = [
collateralAssetUtxo,
iassetUtxo,
priceOracleUtxo,
interestOracleUtxo,
// ref scripts
cdpCreatorRefScriptUtxo,
robScriptRefUtxo,
iAssetTokenPolicyRefScriptUtxo,
cdpAuthTokenPolicyRefScriptUtxo,
...(debtMintingFee > 0n ? [treasuryRefScriptUtxo] : []),
];
const refInputIdxs = getInputIndices(allRefInputs, allRefInputs);
const tx = buildRedemptionsTx(
redemptionRobs,
iassetDatum.assetName,
collateralAssetDatum.collateralAsset,
priceOracleDatum.price,
iassetDatum.redemptionReimbursementRatio,
sysParams,
lucid.newTx(),
0n,
refInputIdxs[0],
refInputIdxs[1],
{ OracleRefInputIdx: refInputIdxs[2] },
);
const txValidity = oracleExpirationAwareValidity(
currentSlot,
Number(sysParams.cdpCreatorParams.biasTime),
Number(priceOracleDatum.expirationTime),
network,
);
tx.validFrom(txValidity.validFrom)
.validTo(txValidity.validTo)
// Ref scripts
.readFrom(allRefInputs)
.mintAssets(cdpNftVal, Data.void())
.mintAssets(iassetTokensVal, Data.void())
.pay.ToContract(
createScriptAddress(network, sysParams.validatorHashes.cdpHash, skh),
{
kind: 'inline',
value: serialiseCdpDatum({
cdpOwner: fromHex(pkh.hash),
iasset: iassetDatum.assetName,
collateralAsset: collateralAssetDatum.collateralAsset,
mintedAmt: mintedAmount,
cdpFees: {
ActiveCDPInterestTracking: {
lastSettled: currentTime,
unitaryInterestSnapshot:
calculateUnitaryInterestSinceOracleLastUpdated(
currentTime,
interestOracleDatum,
) + interestOracleDatum.unitaryInterest,
},
},
}),
},
addAssets(
cdpNftVal,
mkAssetsOf(collateralAssetDatum.collateralAsset, collateralAmount),
),
)
.pay.ToContract(
cdpCreatorUtxo.address,
{
kind: 'inline',
value: serialiseCDPCreatorDatum({
creatorInputOref: {
outputIndex: BigInt(cdpCreatorUtxo.outputIndex),
txHash: fromHex(cdpCreatorUtxo.txHash),
},
}),
},
cdpCreatorUtxo.assets,
);
if (debtMintingFee > 0) {
await treasuryFeeTx(
iassetClass,
debtMintingFee,
0n,
lucid,
sysParams,
tx,
cdpCreatorUtxo,
treasuryOref,
);
}
tx.collectFrom([cdpCreatorUtxo], {
kind: 'self',
makeRedeemer: (inputIdx) => {
return serialiseCDPCreatorRedeemer({
CreateCDP: {
cdpOwner: fromHex(pkh.hash),
minted: mintedAmount,
collateralAmt: collateralAmount,
currentTime: currentTime,
creatorInputIdx: inputIdx,
creatorOutputIdx: BigInt(redemptionRobs.length) + 1n,
cdpOutputIdx: BigInt(redemptionRobs.length),
iassetRefInputIdx: refInputIdxs[1],
collateralAssetRefInputIdx: refInputIdxs[0],
interestOracleRefInputIdx: refInputIdxs[3],
priceOracleIdx: { OracleRefInputIdx: refInputIdxs[2] },
},
});
},
});
return tx;
}
export async function redeemWithCdpClose(
redemptionRobsData: [OutRef, bigint][],
cdpOref: OutRef,
iassetOref: OutRef,
collateralAssetOref: OutRef,
priceOracleOref: OutRef,
interestOracleOref: OutRef,
interestCollectorOref: OutRef,
sysParams: SystemParams,
lucid: LucidEvolution,
currentSlot: number,
): Promise<TxBuilder> {
const network = lucid.config().network!;
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
const robScriptRefUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(sysParams.scriptReferences.robValidatorRef),
]),
(_) => new Error('Expected a single ROB Ref Script UTXO'),
);
const cdpRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(sysParams.scriptReferences.cdpValidatorRef),
]),
(_) => new Error('Expected a single cdp Ref Script UTXO'),
);
const interestCollectorRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.interestCollectionValidatorRef,
),
]),
(_) => new Error('Expected a single interest collector Ref Script UTXO'),
);
const cdpAuthTokenPolicyRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.authTokenPolicies.cdpAuthTokenRef,
),
]),
(_) => new Error('Expected a single cdp auth token policy Ref Script UTXO'),
);
const iAssetTokenPolicyRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.iAssetTokenPolicyRef,
),
]),
(_) => new Error('Expected a single iasset token policy Ref Script UTXO'),
);
const cdpUtxo = matchSingle(
await lucid.utxosByOutRef([cdpOref]),
(_) => new Error('Expected a single cdp UTXO'),
);
const cdpDatum = parseCdpDatumOrThrow(getInlineDatumOrThrow(cdpUtxo));
const collateralAssetUtxo = matchSingle(
await lucid.utxosByOutRef([collateralAssetOref]),
(_) => new Error('Expected a single collateral asset UTXO'),
);
const collateralDatum = parseCollateralAssetDatumOrThrow(
getInlineDatumOrThrow(collateralAssetUtxo),
);
const iassetUtxo = matchSingle(
await lucid.utxosByOutRef([iassetOref]),
(_) => new Error('Expected a single iasset UTXO'),
);
const iassetDatum = parseIAssetDatumOrThrow(
getInlineDatumOrThrow(iassetUtxo),
);
const priceOracleUtxo = matchSingle(
await lucid.utxosByOutRef([priceOracleOref]),
(_) => new Error('Expected a single price oracle UTXO'),
);
const priceOracleDatum = parsePriceOracleDatum(
getInlineDatumOrThrow(priceOracleUtxo),
);
const interestOracleUtxo = matchSingle(
await lucid.utxosByOutRef([interestOracleOref]),
(_) => new Error('Expected a single interest oracle UTXO'),
);
const interestOracleDatum = parseInterestOracleDatum(
getInlineDatumOrThrow(interestOracleUtxo),
);
const interestAmt = match(cdpDatum.cdpFees)
.with({ FrozenCDPAccumulatedFees: P.any }, () => {
throw new Error('CDP fees wrong');
})
.with({ ActiveCDPInterestTracking: P.select() }, (interest) => {
return calculateAccruedInterest(
currentTime,
interest.unitaryInterestSnapshot,
cdpDatum.mintedAmt,
interest.lastSettled,
interestOracleDatum,
);
})
.exhaustive();
const [robsToRedeemOutRefs, robRedemptionIAssetAmt] =
unzip(redemptionRobsData);
const redemptionRobs = await lucid
.utxosByOutRef(robsToRedeemOutRefs)
.then((val) => zip(val, robRedemptionIAssetAmt));
const allRefInputs = [
collateralAssetUtxo,
iassetUtxo,
priceOracleUtxo,
interestOracleUtxo,
// ref scripts
robScriptRefUtxo,
cdpRefScriptUtxo,
iAssetTokenPolicyRefScriptUtxo,
cdpAuthTokenPolicyRefScriptUtxo,
];
const allAll = [
...allRefInputs,
...(interestAmt > 0n ? [interestCollectorRefScriptUtxo] : []),
];
const refInputIdxs = getInputIndices(allRefInputs, allAll);
const tx = buildRedemptionsTx(
redemptionRobs,
iassetDatum.assetName,
collateralDatum.collateralAsset,
priceOracleDatum.price,
iassetDatum.redemptionReimbursementRatio,
sysParams,
lucid.newTx(),
0n,
refInputIdxs[0],
refInputIdxs[1],
{ OracleRefInputIdx: refInputIdxs[2] },
);
const validateFrom = slotToUnixTime(network, currentSlot - 1);
const validateTo = Math.min(
Number(BigInt(validateFrom) + sysParams.cdpParams.biasTime / 2n),
Number(priceOracleDatum.expirationTime - 1n * 1000n),
);
tx.validFrom(validateFrom)
.validTo(validateTo)
.readFrom(allRefInputs)
.mintAssets(
mkAssetsOf(
{
currencySymbol: fromHex(
sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
),
tokenName: collateralDatum.iasset,
},
-cdpDatum.mintedAmt,
),
Data.void(),
)
.mintAssets(
mkAssetsOf(fromSystemParamsAsset(sysParams.cdpParams.cdpAuthToken), -1n),
Data.void(),
)
.collectFrom(
[cdpUtxo],
serialiseCdpRedeemer({ CloseCdp: { currentTime: currentTime } }),
)
// TODO: this is just a placeholder
.setMinFee(3_000_000n);
if (!cdpDatum.cdpOwner) {
throw new Error('Expected active CDP');
}
tx.addSignerKey(toHex(cdpDatum.cdpOwner));
if (interestAmt > 0n) {
await collectInterestTx(
mkAssetsOf(
{
currencySymbol: fromHex(
sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
),
tokenName: collateralDatum.iasset,
},
interestAmt,
),
lucid,
sysParams,
tx,
interestCollectorOref,
);
}
return tx;
}
export async function redeemWithCdpAdjust(
redemptionRobsData: [OutRef, bigint][],
/// cdp adjust params
collateralAdjustment: bigint,
debtAdjustment: bigint,
cdpOref: OutRef,
iassetOref: OutRef,
collateralAssetOref: OutRef,
priceOracleOref: OutRef,
interestOracleOref: OutRef,
treasuryOref: OutRef,
interestCollectorOref: OutRef,
currentSlot: number,
lucid: LucidEvolution,
sysParams: SystemParams,
): Promise<TxBuilder> {
const network = lucid.config().network!;
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
const robScriptRefUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(sysParams.scriptReferences.robValidatorRef),
]),
(_) => new Error('Expected a single ROB Ref Script UTXO'),
);
const cdpRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(sysParams.scriptReferences.cdpValidatorRef),
]),
(_) => new Error('Expected a single cdp Ref Script UTXO'),
);
const iAssetTokenPolicyRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.iAssetTokenPolicyRef,
),
]),
(_) => new Error('Expected a single iasset token policy Ref Script UTXO'),
);
const interestCollectorRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.interestCollectionValidatorRef,
),
]),
(_) => new Error('Expected a single interest collector Ref Script UTXO'),
);
const treasuryRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.treasuryValidatorRef,
),
]),
(_) => new Error('Expected a single treasury Ref Script UTXO'),
);
const cdpUtxo = matchSingle(
await lucid.utxosByOutRef([cdpOref]),
(_) => new Error('Expected a single cdp UTXO'),
);
const cdpDatum = parseCdpDatumOrThrow(getInlineDatumOrThrow(cdpUtxo));
const iassetUtxo = matchSingle(
await lucid.utxosByOutRef([iassetOref]),
(_) => new Error('Expected a single iasset UTXO'),
);
const iassetDatum = parseIAssetDatumOrThrow(
getInlineDatumOrThrow(iassetUtxo),
);
const collateralAssetUtxo = matchSingle(
await lucid.utxosByOutRef([collateralAssetOref]),
(_) => new Error('Expected a single collateral asset UTXO'),
);
const collateralAssetDatum = parseCollateralAssetDatumOrThrow(
getInlineDatumOrThrow(collateralAssetUtxo),
);
const priceOracleUtxo = matchSingle(
await lucid.utxosByOutRef([priceOracleOref]),
(_) => new Error('Expected a single price oracle UTXO'),
);
const priceOracleDatum = parsePriceOracleDatum(
getInlineDatumOrThrow(priceOracleUtxo),
);
const interestOracleUtxo = matchSingle(
await lucid.utxosByOutRef([interestOracleOref]),
(_) => new Error('Expected a single interest oracle UTXO'),
);
const interestOracleDatum = parseInterestOracleDatum(
getInlineDatumOrThrow(interestOracleUtxo),
);
const interestAmt = match(cdpDatum.cdpFees)
.with({ FrozenCDPAccumulatedFees: P.any }, () => {
throw new Error('CDP fees wrong');
})
.with({ ActiveCDPInterestTracking: P.select() }, (interest) => {
return calculateAccruedInterest(
currentTime,
interest.unitaryInterestSnapshot,
cdpDatum.mintedAmt,
interest.lastSettled,
interestOracleDatum,
);
})
.exhaustive();
const mintedAmountChange = debtAdjustment + interestAmt;
let treasuryFee = 0n;
// when mint
if (debtAdjustment > 0n) {
treasuryFee += calculateFeeFromRatio(
iassetDatum.debtMintingFeeRatio,
debtAdjustment,
);
}
const [robsToRedeemOutRefs, robRedemptionIAssetAmt] =
unzip(redemptionRobsData);
const redemptionRobs = await lucid
.utxosByOutRef(robsToRedeemOutRefs)
.then((val) => zip(val, robRedemptionIAssetAmt));
const allRefInputs = [
collateralAssetUtxo,
iassetUtxo,
priceOracleUtxo,
interestOracleUtxo,
// ref scripts
robScriptRefUtxo,
cdpRefScriptUtxo,
iAssetTokenPolicyRefScriptUtxo,
];
const allAll = [
...allRefInputs,
...(interestAmt > 0n ? [interestCollectorRefScriptUtxo] : []),
...(treasuryFee > 0n ? [treasuryRefScriptUtxo] : []),
];
const refInputIdxs = getInputIndices(allRefInputs, allAll);
const tx = buildRedemptionsTx(
redemptionRobs,
iassetDatum.assetName,
collateralAssetDatum.collateralAsset,
priceOracleDatum.price,
iassetDatum.redemptionReimbursementRatio,
sysParams,
lucid.newTx(),
0n,
refInputIdxs[0],
refInputIdxs[1],
{ OracleRefInputIdx: refInputIdxs[2] },
);
const txValidity = oracleExpirationAwareValidity(
currentSlot,
Number(sysParams.cdpCreatorParams.biasTime),
Number(priceOracleDatum.expirationTime),
network,
);
tx.validFrom(txValidity.validFrom)
.validTo(txValidity.validTo)
.readFrom(allRefInputs)
.collectFrom(
[cdpUtxo],
serialiseCdpRedeemer({
AdjustCdp: {
currentTime: currentTime,
debtAdjustment: debtAdjustment,
collateralAdjustment,
priceOracleIdx: { OracleRefInputIdx: refInputIdxs[2] },
},
}),
)
.pay.ToContract(
cdpUtxo.address,
{
kind: 'inline',
value: serialiseCdpDatum({
...cdpDatum,
mintedAmt: cdpDatum.mintedAmt + mintedAmountChange,
cdpFees: {
ActiveCDPInterestTracking: {
lastSettled: currentTime,
unitaryInterestSnapshot:
calculateUnitaryInterestSinceOracleLastUpdated(
currentTime,
interestOracleDatum,
) + interestOracleDatum.unitaryInterest,
},
},
}),
},
addAssets(
cdpUtxo.assets,
mkAssetsOf(cdpDatum.collateralAsset, collateralAdjustment),
),
);
if (!cdpDatum.cdpOwner) {
throw new Error('Expected active CDP');
}
tx.addSignerKey(toHex(cdpDatum.cdpOwner));
const iAssetAc = {
currencySymbol: fromHex(
sysParams.cdpParams.cdpAssetSymbol.unCurrencySymbol,
),
tokenName: iassetDatum.assetName,
};
if (mintedAmountChange !== 0n) {
const iassetTokensVal = mkAssetsOf(iAssetAc, mintedAmountChange);
tx.mintAssets(iassetTokensVal, Data.void());
}
if (interestAmt > 0n) {
await collectInterestTx(
mkAssetsOf(iAssetAc, interestAmt),
lucid,
sysParams,
tx,
interestCollectorOref,
);
}
if (treasuryFee > 0n) {
await treasuryFeeTx(
iAssetAc,
treasuryFee,
0n,
lucid,
sysParams,
tx,
cdpOref,
treasuryOref,
);
}
return tx;
}