UNPKG

@indigo-labs/indigo-sdk

Version:

Indigo SDK for interacting with Indigo endpoints via lucid-evolution

856 lines (760 loc) 23.9 kB
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; }