@indigo-labs/indigo-sdk
Version:
Indigo SDK for interacting with Indigo endpoints via lucid-evolution
923 lines (844 loc) • 26.1 kB
text/typescript
import {
fromText,
LucidEvolution,
TxBuilder,
Data,
UTxO,
fromHex,
toHex,
addAssets,
OutRef,
slotToUnixTime,
credentialToAddress,
} from '@lucid-evolution/lucid';
import {
fromSysParamsCredential,
fromSystemParamsAsset,
fromSystemParamsScriptRef,
SystemParams,
} from '../../types/system-params';
import { addrDetails, getInlineDatumOrThrow } from '../../utils/lucid-utils';
import {
BASE_MAX_TX_FEE,
createProcessRequestAccountRedeemer,
findRelevantE2s2sIdxs,
initSpState,
liquidationHelper,
partitionEpochToScaleToSums,
updateAccount,
updatePoolStateWhenWithdrawalFee,
} from './helpers';
import { calculateFeeFromRatio } from '../../utils/indigo-helpers';
import {
AccountAction,
AccountContent,
fromSPInteger,
mkSPInteger,
parseAccountDatumOrThrow,
parseStabilityPoolDatumOrThrow,
serialiseActionReturnDatum,
serialiseStabilityPoolDatum,
serialiseStabilityPoolRedeemer,
spAdd,
spSub,
spZeroNegatives,
} from './types-new';
import {
adaAssetClass,
addressFromBech32,
addressToBech32,
AssetClass,
assetClassValueOf,
estimateUtxoMinLovelace,
lovelacesAmt,
matchSingle,
mkAssetsOf,
mkLovelacesOf,
negateAssets,
} from '@3rd-eye-labs/cardano-offchain-common';
import { parseIAssetDatumOrThrow } from '../iasset/types';
import { match, P } from 'ts-pattern';
import { bigintMax, zeroNegatives } from '../../utils/bigint-utils';
export async function requestSpAccountCreation(
assetAscii: string,
amount: bigint,
sysParams: SystemParams,
lucid: LucidEvolution,
): Promise<TxBuilder> {
const [pkh, _skh] = await addrDetails(lucid);
const iasset = fromHex(fromText(assetAscii));
const iassetAssetClass = {
currencySymbol: fromHex(
sysParams.stabilityPoolParams.assetSymbol.unCurrencySymbol,
),
tokenName: iasset,
};
const datum: AccountContent = {
owner: fromHex(pkh.hash),
iasset: iasset,
state: { ...initSpState, depositVal: mkSPInteger(amount) },
assetSums: [],
request: 'Create',
lastRequestProcessingTime: 0n,
};
return lucid
.newTx()
.pay.ToContract(
credentialToAddress(
lucid.config().network!,
{
hash: sysParams.validatorHashes.stabilityPoolHash,
type: 'Script',
},
sysParams.stabilityPoolParams.stakeCredential != null
? fromSysParamsCredential(
sysParams.stabilityPoolParams.stakeCredential,
)
: undefined,
),
{
kind: 'inline',
value: serialiseStabilityPoolDatum({ Account: datum }),
},
addAssets(
mkAssetsOf(iassetAssetClass, amount),
mkLovelacesOf(
// TODO: Calculate a more accurate amount to just cover costs.
// This should cover the account creation fee,
// the minimum ADA for the account UTxO and the transaction fee.
BigInt(sysParams.stabilityPoolParams.accountCreateFeeLovelaces) +
3_000_000n,
),
),
)
.addSignerKey(pkh.hash);
}
export async function requestSpAccountAdjustment(
amount: bigint,
accountUtxo: UTxO,
sysParams: SystemParams,
lucid: LucidEvolution,
): Promise<TxBuilder> {
const myAddress = await lucid.wallet().address();
const stabilityPoolScriptRef = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.stabilityPoolValidatorRef,
),
]),
(_) => new Error('Expected a single stability pool Ref Script UTXO'),
);
const oldAccountDatum: AccountContent = parseAccountDatumOrThrow(
getInlineDatumOrThrow(accountUtxo),
);
const newAccountDatum: AccountContent = {
...oldAccountDatum,
request: {
Adjust: {
amount: amount,
outputAddress: addressFromBech32(myAddress),
},
},
};
return lucid
.newTx()
.readFrom([stabilityPoolScriptRef])
.collectFrom(
[accountUtxo],
serialiseStabilityPoolRedeemer({
RequestAction: {
Adjust: {
amount: amount,
outputAddress: addressFromBech32(myAddress),
},
},
}),
)
.pay.ToContract(
accountUtxo.address,
{
kind: 'inline',
value: serialiseStabilityPoolDatum({
Account: newAccountDatum,
}),
},
addAssets(
mkLovelacesOf(
// TODO: Calculate a more accurate amount to just cover costs.
// This should cover the minimum ADA for 2 UTxOs (account and
// rewards withdrawal) and the transaction fee.
5_000_000n,
),
mkAssetsOf(
fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
1n,
),
amount > 0n
? mkAssetsOf(
{
currencySymbol: fromHex(
sysParams.stabilityPoolParams.assetSymbol.unCurrencySymbol,
),
tokenName: oldAccountDatum.iasset,
},
amount,
)
: {},
),
)
.addSignerKey(toHex(oldAccountDatum.owner));
}
export async function requestSpAccountClosure(
accountUtxo: UTxO,
sysParams: SystemParams,
lucid: LucidEvolution,
maxTxFee: bigint = BASE_MAX_TX_FEE,
): Promise<TxBuilder> {
const myAddress = await lucid.wallet().address();
const stabilityPoolScriptRef = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.stabilityPoolValidatorRef,
),
]),
(_) => new Error('Expected a single stability pool Ref Script UTXO'),
);
const request: AccountAction = {
Close: {
outputAddress: addressFromBech32(myAddress),
maxTxFee: maxTxFee,
},
};
const oldAccountDatum: AccountContent = parseAccountDatumOrThrow(
getInlineDatumOrThrow(accountUtxo),
);
const newAccountDatum: AccountContent = {
...oldAccountDatum,
request: request,
};
return lucid
.newTx()
.readFrom([stabilityPoolScriptRef])
.collectFrom(
[accountUtxo],
serialiseStabilityPoolRedeemer({ RequestAction: request }),
)
.pay.ToContract(
accountUtxo.address,
{
kind: 'inline',
value: serialiseStabilityPoolDatum({ Account: newAccountDatum }),
},
addAssets(
mkLovelacesOf(
// TODO: Calculate a more accurate amount to just cover costs.
// This should cover the minimum ADA for the rewards UTxO and the transaction fee.
3_000_000n,
),
mkAssetsOf(
fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
1n,
),
),
)
.addSignerKey(toHex(oldAccountDatum.owner));
}
async function processSpRequestAuxiliary(
stabilityPoolUtxo: UTxO,
accountUtxo: UTxO,
iAssetUtxo: UTxO,
/**
* For performance provide only the ones related to the pool's iAsset.
*/
allE2s2sSnapshotOrefs: OutRef[],
sysParams: SystemParams,
lucid: LucidEvolution,
currentSlot: number,
txFee: bigint,
): Promise<TxBuilder> {
const network = lucid.config().network!;
const currentTime = BigInt(slotToUnixTime(network, currentSlot));
const stabilityPoolScriptRef = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.stabilityPoolValidatorRef,
),
]),
(_) => new Error('Expected a single stability pool Ref Script UTXO'),
);
const accountDatum = parseAccountDatumOrThrow(
getInlineDatumOrThrow(accountUtxo),
);
const stabilityPoolDatum = parseStabilityPoolDatumOrThrow(
getInlineDatumOrThrow(stabilityPoolUtxo),
);
const baseRefInputs = [iAssetUtxo, stabilityPoolScriptRef];
const validFrom = slotToUnixTime(network, currentSlot - 1);
const tx = lucid
.newTx()
.validFrom(validFrom)
.validTo(validFrom + sysParams.stabilityPoolParams.accountProcessingBiasMs)
.readFrom(baseRefInputs)
.collectFrom([stabilityPoolUtxo], {
kind: 'selected',
inputs: [stabilityPoolUtxo, accountUtxo],
makeRedeemer: (indices) =>
serialiseStabilityPoolRedeemer({
ProcessRequestPool: {
poolInputIdx: indices[0],
accountInputIdx: indices[1],
},
}),
});
if (!accountDatum.request) throw new Error('Account Request is null');
const iassetAssetClass: AssetClass = {
currencySymbol: fromHex(
sysParams.stabilityPoolParams.assetSymbol.unCurrencySymbol,
),
tokenName: stabilityPoolDatum.iasset,
};
await match(accountDatum.request)
.with('Create', async (_) => {
const accountTokenScriptRef = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.authTokenPolicies.accountTokenRef,
),
]),
(_) =>
new Error('Expected a single cdp auth token policy Ref Script UTXO'),
);
const requestDepositAmt = assetClassValueOf(
accountUtxo.assets,
iassetAssetClass,
);
const poolAddr = credentialToAddress(
lucid.config().network!,
{
hash: sysParams.validatorHashes.stabilityPoolHash,
type: 'Script',
},
sysParams.stabilityPoolParams.stakeCredential != null
? fromSysParamsCredential(
sysParams.stabilityPoolParams.stakeCredential,
)
: undefined,
);
const accountOutputAdaAmt =
lovelacesAmt(accountUtxo.assets) -
BigInt(sysParams.stabilityPoolParams.accountCreateFeeLovelaces) -
txFee;
const accountTokenVal = mkAssetsOf(
fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
1n,
);
const accountOutputDatum = serialiseStabilityPoolDatum({
Account: {
owner: accountDatum.owner,
iasset: stabilityPoolDatum.iasset,
state: {
...stabilityPoolDatum.state,
depositVal: mkSPInteger(requestDepositAmt),
},
assetSums: stabilityPoolDatum.assetStates.map(([key, val]) => [
key,
val.currentSumVal,
]),
request: null,
lastRequestProcessingTime: currentTime,
},
});
const accountOutMinUtxoLovelace = estimateUtxoMinLovelace(
lucid.config().protocolParameters!,
poolAddr,
accountTokenVal,
{ InlineDatum: { datum: accountOutputDatum } },
);
// This is to prevent spending ADA from the wallet submitting the request processing Tx.
if (accountOutputAdaAmt < accountOutMinUtxoLovelace) {
throw new Error("Request doesn't have enough ADA to be processed.");
}
tx.readFrom([accountTokenScriptRef])
.collectFrom([accountUtxo], {
kind: 'selected',
inputs: [stabilityPoolUtxo, accountUtxo],
makeRedeemer: (indices) =>
serialiseStabilityPoolRedeemer({
ProcessRequestAccount: {
poolInputIdx: indices[0],
accountInputIdx: indices[1],
e2s2sIdxs: [],
currentTime: currentTime,
},
}),
})
.mintAssets(accountTokenVal, Data.void())
.pay.ToContract(
poolAddr,
{
kind: 'inline',
value: serialiseStabilityPoolDatum({
StabilityPool: liquidationHelper(
{
...stabilityPoolDatum,
state: {
...stabilityPoolDatum.state,
depositVal: spAdd(
stabilityPoolDatum.state.depositVal,
mkSPInteger(requestDepositAmt),
),
},
},
adaAssetClass,
0n,
BigInt(sysParams.stabilityPoolParams.accountCreateFeeLovelaces),
),
}),
},
addAssets(
stabilityPoolUtxo.assets,
mkAssetsOf(iassetAssetClass, requestDepositAmt),
mkLovelacesOf(
BigInt(sysParams.stabilityPoolParams.accountCreateFeeLovelaces),
),
),
)
.pay.ToContract(
poolAddr,
{
kind: 'inline',
value: accountOutputDatum,
},
addAssets(accountTokenVal, mkLovelacesOf(accountOutputAdaAmt)),
)
.setMinFee(txFee);
})
.with({ Adjust: P.select() }, async (adjustContent) => {
const iassetDatum = parseIAssetDatumOrThrow(
getInlineDatumOrThrow(iAssetUtxo),
);
const accountDepositChange = adjustContent.amount;
const outputAddress = addressToBech32(
adjustContent.outputAddress,
lucid.config().network!,
);
const e2s2sIdxs = await findRelevantE2s2sIdxs(
lucid,
stabilityPoolDatum,
accountDatum.state,
allE2s2sSnapshotOrefs,
);
const { updatedAccountContent, reward } = updateAccount(
stabilityPoolDatum,
accountDatum,
e2s2sIdxs,
);
const isDepositOrRewardWithdrawal = accountDepositChange >= 0;
const accountBalanceChange = isDepositOrRewardWithdrawal
? accountDepositChange
: bigintMax(
accountDepositChange,
-fromSPInteger(updatedAccountContent.state.depositVal),
);
const newPoolDepositExcludingFee = spZeroNegatives(
spAdd(
stabilityPoolDatum.state.depositVal,
mkSPInteger(accountBalanceChange),
),
);
const withdrawalFeeAmt =
isDepositOrRewardWithdrawal || newPoolDepositExcludingFee.value === 0n
? 0n
: calculateFeeFromRatio(
iassetDatum.stabilityPoolWithdrawalFeeRatio,
-accountBalanceChange,
);
const newPoolState = updatePoolStateWhenWithdrawalFee(withdrawalFeeAmt, {
...stabilityPoolDatum.state,
depositVal: newPoolDepositExcludingFee,
});
const { e2s2sRefInputs, mkProcessRequestAccountRedeemerContent } =
createProcessRequestAccountRedeemer(
e2s2sIdxs,
baseRefInputs,
currentTime,
);
if (e2s2sRefInputs.length > 0) {
tx.readFrom(e2s2sRefInputs);
}
tx.collectFrom([accountUtxo], {
kind: 'selected',
inputs: [stabilityPoolUtxo, accountUtxo],
makeRedeemer: (indices) => {
return serialiseStabilityPoolRedeemer({
ProcessRequestAccount: mkProcessRequestAccountRedeemerContent(
indices[0],
indices[1],
),
});
},
}).pay.ToContract(
stabilityPoolUtxo.address,
{
kind: 'inline',
value: serialiseStabilityPoolDatum({
StabilityPool: {
...stabilityPoolDatum,
state: newPoolState,
},
}),
},
addAssets(
stabilityPoolUtxo.assets,
negateAssets(reward),
mkAssetsOf(iassetAssetClass, accountBalanceChange + withdrawalFeeAmt),
),
);
const theoreticalOwnerOutputVal = addAssets(
reward,
isDepositOrRewardWithdrawal
? {}
: mkAssetsOf(
iassetAssetClass,
-accountBalanceChange - withdrawalFeeAmt,
),
);
const ownerOutputDat = serialiseActionReturnDatum({
IndigoStabilityPoolAccountAdjustment: {
txHash: fromHex(accountUtxo.txHash),
outputIndex: BigInt(accountUtxo.outputIndex),
},
});
const ownerOutputMinUtxoLovelace = estimateUtxoMinLovelace(
lucid.config().protocolParameters!,
outputAddress,
theoreticalOwnerOutputVal,
{ InlineDatum: { datum: ownerOutputDat } },
);
// Add extra lovelaces only when needed to reach minUTxo lovelaces.
const extraOwnerOutputLovelacesAmt =
lovelacesAmt(theoreticalOwnerOutputVal) >= ownerOutputMinUtxoLovelace
? 0n
: ownerOutputMinUtxoLovelace -
lovelacesAmt(theoreticalOwnerOutputVal);
const actualOwnerOutputVal = addAssets(
theoreticalOwnerOutputVal,
mkLovelacesOf(extraOwnerOutputLovelacesAmt),
);
const accountOutputDat = serialiseStabilityPoolDatum({
Account: {
...updatedAccountContent,
state: {
...updatedAccountContent.state,
depositVal: spAdd(
updatedAccountContent.state.depositVal,
mkSPInteger(accountBalanceChange),
),
},
request: null,
lastRequestProcessingTime: currentTime,
},
});
const accountOutputValWithoutAda = mkAssetsOf(
fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
1n,
);
const accountOutMinUtxoLovelace = estimateUtxoMinLovelace(
lucid.config().protocolParameters!,
stabilityPoolUtxo.address,
accountOutputValWithoutAda,
{ InlineDatum: { datum: accountOutputDat } },
);
const accountOutputAdaAmt =
lovelacesAmt(accountUtxo.assets) - extraOwnerOutputLovelacesAmt - txFee;
// This is to prevent spending ADA from the wallet submitting the request processing Tx.
if (accountOutputAdaAmt < accountOutMinUtxoLovelace) {
throw new Error("Account doesn't have enough ADA to be processed.");
}
tx.pay
.ToContract(
stabilityPoolUtxo.address,
{
kind: 'inline',
value: accountOutputDat,
},
addAssets(
accountOutputValWithoutAda,
mkLovelacesOf(accountOutputAdaAmt),
),
)
.pay.ToAddressWithData(
outputAddress,
{
kind: 'inline',
value: ownerOutputDat,
},
actualOwnerOutputVal,
)
.setMinFee(txFee);
})
.with({ Close: P.select() }, async (closeContent) => {
if (txFee > closeContent.maxTxFee) {
throw new Error("Account doesn't allow current transaction fee.");
}
const accountTokenScriptRef = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.authTokenPolicies.accountTokenRef,
),
]),
(_) =>
new Error('Expected a single cdp auth token policy Ref Script UTXO'),
);
const iassetDatum = parseIAssetDatumOrThrow(
getInlineDatumOrThrow(iAssetUtxo),
);
const outputAddress = addressToBech32(
closeContent.outputAddress,
lucid.config().network!,
);
const e2s2sIdxs = await findRelevantE2s2sIdxs(
lucid,
stabilityPoolDatum,
accountDatum.state,
allE2s2sSnapshotOrefs,
);
const { updatedAccountContent, reward } = updateAccount(
stabilityPoolDatum,
accountDatum,
e2s2sIdxs,
);
const newPoolDepositExcludingFee = spZeroNegatives(
spSub(
stabilityPoolDatum.state.depositVal,
updatedAccountContent.state.depositVal,
),
);
const withdrawnAmt = zeroNegatives(
fromSPInteger(updatedAccountContent.state.depositVal),
);
const withdrawalFeeAmt =
newPoolDepositExcludingFee.value === 0n
? 0n
: calculateFeeFromRatio(
iassetDatum.stabilityPoolWithdrawalFeeRatio,
withdrawnAmt,
);
const newPoolState = updatePoolStateWhenWithdrawalFee(withdrawalFeeAmt, {
...stabilityPoolDatum.state,
depositVal: newPoolDepositExcludingFee,
});
const { e2s2sRefInputs, mkProcessRequestAccountRedeemerContent } =
createProcessRequestAccountRedeemer(
e2s2sIdxs,
[...baseRefInputs, accountTokenScriptRef],
currentTime,
);
if (e2s2sRefInputs.length > 0) {
tx.readFrom(e2s2sRefInputs);
}
tx.readFrom([accountTokenScriptRef])
.collectFrom([accountUtxo], {
kind: 'selected',
inputs: [stabilityPoolUtxo, accountUtxo],
makeRedeemer: (indices) => {
return serialiseStabilityPoolRedeemer({
ProcessRequestAccount: mkProcessRequestAccountRedeemerContent(
indices[0],
indices[1],
),
});
},
})
.mintAssets(
mkAssetsOf(
fromSystemParamsAsset(sysParams.stabilityPoolParams.accountToken),
-1n,
),
Data.void(),
)
.pay.ToContract(
stabilityPoolUtxo.address,
{
kind: 'inline',
value: serialiseStabilityPoolDatum({
StabilityPool: {
...stabilityPoolDatum,
state: newPoolState,
},
}),
},
addAssets(
stabilityPoolUtxo.assets,
negateAssets(reward),
mkAssetsOf(iassetAssetClass, -withdrawnAmt + withdrawalFeeAmt),
),
)
.pay.ToAddressWithData(
outputAddress,
{
kind: 'inline',
value: serialiseActionReturnDatum({
IndigoStabilityPoolAccountClosure: {
txHash: fromHex(accountUtxo.txHash),
outputIndex: BigInt(accountUtxo.outputIndex),
},
}),
},
addAssets(
mkLovelacesOf(lovelacesAmt(accountUtxo.assets) - txFee),
reward,
mkAssetsOf(iassetAssetClass, withdrawnAmt - withdrawalFeeAmt),
),
)
.setMinFee(txFee);
})
.exhaustive();
return tx;
}
export async function processSpRequest(
stabilityPoolUtxo: UTxO,
accountUtxo: UTxO,
iAssetUtxo: UTxO,
/**
* For performance provide only the ones related to the pool's iAsset.
*/
allE2s2sSnapshotOrefs: OutRef[],
sysParams: SystemParams,
lucid: LucidEvolution,
currentSlot: number,
): Promise<TxBuilder> {
const draftTx = processSpRequestAuxiliary(
stabilityPoolUtxo,
accountUtxo,
iAssetUtxo,
allE2s2sSnapshotOrefs,
sysParams,
lucid,
currentSlot,
// Placeholder transation fee
1n,
);
const fee = (await (await draftTx).complete()).toTransaction().body().fee();
return processSpRequestAuxiliary(
stabilityPoolUtxo,
accountUtxo,
iAssetUtxo,
allE2s2sSnapshotOrefs,
sysParams,
lucid,
currentSlot,
fee,
);
}
export async function createE2s2sSnapshots(
stabilityPoolOref: OutRef,
sysParams: SystemParams,
lucid: LucidEvolution,
): Promise<TxBuilder> {
const stabilityPoolRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.stabilityPoolValidatorRef,
),
]),
(_) => new Error('Expected a single stability pool Ref Script UTXO'),
);
const snapshotE2s2sPolicyRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
sysParams.scriptReferences.authTokenPolicies
.snapshotEpochToScaleToSumTokenRef,
),
]),
(_) => new Error('Expected a single snapshot e2s2s policy Ref Script UTXO'),
);
const spUtxo = matchSingle(
await lucid.utxosByOutRef([stabilityPoolOref]),
(_) => new Error('Expected a single stability pool UTXO'),
);
const spDatum = parseStabilityPoolDatumOrThrow(getInlineDatumOrThrow(spUtxo));
const [newSnapshotDatums, newAssetStates] =
partitionEpochToScaleToSums(spDatum);
if (newSnapshotDatums.length === 0) {
throw new Error('There has to be a snapshot being created.');
}
const snapshotAc = fromSystemParamsAsset(
sysParams.stabilityPoolParams.snapshotEpochToScaleToSumToken,
);
const tx = lucid
.newTx()
.readFrom([stabilityPoolRefScriptUtxo, snapshotE2s2sPolicyRefScriptUtxo])
.collectFrom(
[spUtxo],
serialiseStabilityPoolRedeemer('RecordEpochToScaleToSum'),
)
.mintAssets(
mkAssetsOf(snapshotAc, BigInt(newSnapshotDatums.length)),
Data.void(),
)
.pay.ToContract(
spUtxo.address,
{
kind: 'inline',
value: serialiseStabilityPoolDatum({
StabilityPool: { ...spDatum, assetStates: newAssetStates },
}),
},
spUtxo.assets,
);
for (const newDatum of newSnapshotDatums) {
tx.pay.ToContract(
spUtxo.address,
{
kind: 'inline',
value: serialiseStabilityPoolDatum({
SnapshotEpochToScaleToSum: newDatum,
}),
},
mkAssetsOf(snapshotAc, 1n),
);
}
return tx;
}
export async function annulRequest(
accountUtxo: UTxO,
params: SystemParams,
lucid: LucidEvolution,
): Promise<TxBuilder> {
const stabilityPoolRefScriptUtxo = matchSingle(
await lucid.utxosByOutRef([
fromSystemParamsScriptRef(
params.scriptReferences.stabilityPoolValidatorRef,
),
]),
(_) => new Error('Expected a single stability pool Ref Script UTXO'),
);
const oldAccountDatum: AccountContent = parseAccountDatumOrThrow(
getInlineDatumOrThrow(accountUtxo),
);
const tx = lucid
.newTx()
.readFrom([stabilityPoolRefScriptUtxo])
.collectFrom([accountUtxo], serialiseStabilityPoolRedeemer('AnnulRequest'))
.addSignerKey(toHex(oldAccountDatum.owner));
if (oldAccountDatum.request !== 'Create') {
tx.pay.ToContract(
accountUtxo.address,
{
kind: 'inline',
value: serialiseStabilityPoolDatum({
Account: {
...oldAccountDatum,
request: null,
},
}),
},
mkAssetsOf(
fromSystemParamsAsset(params.stabilityPoolParams.accountToken),
1n,
),
);
}
return tx;
}