UNPKG

@indigo-labs/indigo-sdk

Version:

Indigo SDK for interacting with Indigo endpoints via lucid-evolution

352 lines (331 loc) 9.99 kB
import { pipe } from 'fp-ts/lib/function'; import { array as A, option as O, string as S, ord as Ord, function as F, } from 'fp-ts'; import { addAssets, Assets, LucidEvolution, OutRef, toHex, toText, UTxO, } from '@lucid-evolution/lucid'; import { matchSingle } from '../../utils/utils'; import { getInlineDatumOrThrow } from '../../utils/lucid-utils'; import { AddCollateralAsssetContent, ProposeAssetContent, TreasuryWithdrawal, TreasuryWithdrawalItem, } from './types-new'; import { AssetClass, mkAssetsOf } from '@3rd-eye-labs/cardano-offchain-common'; import { CollateralAssetContent, CollateralAssetOutput, IAssetContent, IAssetOutput, parseCollateralAssetDatumOrThrow, parseIAssetDatumOrThrow, } from '../iasset/types'; import { getAssetClassComparisonStr, ParsedOutput } from '../../types/generic'; export function proposalDeposit( baseDeposit: bigint, activeProposals: bigint, ): bigint { return baseDeposit * 2n ** activeProposals; } export function createValueFromWithdrawal(w: TreasuryWithdrawal): Assets { return A.reduce<TreasuryWithdrawalItem, Assets>({}, (acc, item) => addAssets( acc, mkAssetsOf( { currencySymbol: item.currencySymbol, tokenName: item.tokenName, }, item.amount, ), ), )([...w.value]); } /** * A generic solution for iassets and collateral assets chain. */ async function findRelativeAssetForInsertion< T extends Uint8Array<ArrayBufferLike> | AssetClass, K, >( newAsset: T, allIAssetOrefs: OutRef[], lucid: LucidEvolution, assetOrd: Ord.Ord<T>, getComparisonAsset: (datum: K) => T, parseDatum: (utxo: UTxO) => K, ): Promise<O.Option<ParsedOutput<K>>> { const parsedUtxos = await Promise.all( allIAssetOrefs.map(async (oref) => { const utxo = matchSingle( await lucid.utxosByOutRef([oref]), (_) => new Error('Expected a single UTXO'), ); const datum = parseDatum(utxo); return { datum: datum, utxo: utxo }; }), ); // The iasset just before the new token name based on assets ordering return pipe( parsedUtxos, // Sort by the asset names A.sort( Ord.contramap<T, ParsedOutput<K>>((a) => getComparisonAsset(a.datum))( assetOrd, ), ), // split head and tail A.foldLeft( () => O.none, (head, rest) => O.some<[ParsedOutput<K>, ParsedOutput<K>[]]>([head, rest]), ), // find the preceding iasset for the new token name O.flatMap(([firstIAsset, rest]) => O.some( A.reduce<ParsedOutput<K>, ParsedOutput<K>>( firstIAsset, (acc, iasset) => { const isGreater = assetOrd.compare(getComparisonAsset(iasset.datum), newAsset) === -1; // When the new asset is greater, stop searching for the reference. return isGreater ? iasset : acc; }, )(rest), ), ), ); } /** * Find the IAsset that should be a preceding one for the new IAsset token name. * In case there are no iassets, none should be returned. */ export async function findRelativeIAssetForInsertion( newIAssetTokenName: Uint8Array<ArrayBufferLike>, allIAssetOrefs: OutRef[], lucid: LucidEvolution, ): Promise<O.Option<IAssetOutput>> { return findRelativeAssetForInsertion( newIAssetTokenName, allIAssetOrefs, lucid, Ord.contramap<string, Uint8Array<ArrayBufferLike>>((x) => toText(toHex(x)))( S.Ord, ), (d) => d.assetName, (utxo) => parseIAssetDatumOrThrow(getInlineDatumOrThrow(utxo)), ); } /** * Find collateral asset that should be a preceding one for the new Collateral asset. * In case there are no collateral assets, none should be returned. */ export async function findRelativeCollateralAssetForInsertion( newCollateralAsset: AssetClass, allCollateralAssetOrefs: OutRef[], lucid: LucidEvolution, ): Promise<O.Option<CollateralAssetOutput>> { return findRelativeAssetForInsertion( newCollateralAsset, allCollateralAssetOrefs, lucid, Ord.contramap<string, AssetClass>((x) => getAssetClassComparisonStr(x))( S.Ord, ), (d) => d.collateralAsset, (utxo) => parseCollateralAssetDatumOrThrow(getInlineDatumOrThrow(utxo)), ); } /** * A generic solution for iassets and collateral assets chain. */ async function findFirstAsset< T extends Uint8Array<ArrayBufferLike> | AssetClass, K, >( allIAssetOrefs: OutRef[], lucid: LucidEvolution, assetOrd: Ord.Ord<T>, getComparisonAsset: (datum: K) => T, parseDatum: (utxo: UTxO) => K, ): Promise<O.Option<ParsedOutput<K>>> { const parsedUtxos = await Promise.all( allIAssetOrefs.map(async (oref) => { const utxo = matchSingle( await lucid.utxosByOutRef([oref]), (_) => new Error('Expected a single UTXO'), ); const datum = parseDatum(utxo); return { datum: datum, utxo: utxo }; }), ); // The iasset just before the new token name based on assets ordering return pipe( parsedUtxos, // Sort by the asset names A.sort( Ord.contramap<T, ParsedOutput<K>>((a) => getComparisonAsset(a.datum))( assetOrd, ), ), A.head, ); } /** * Find the collateral asset that is first in the distributed list. * In case there are no collateral assets, none should be returned. */ export async function findFirstCollateralAsset( allCollateralAssetOrefs: OutRef[], lucid: LucidEvolution, ): Promise<O.Option<CollateralAssetOutput>> { return findFirstAsset( allCollateralAssetOrefs, lucid, Ord.contramap<string, AssetClass>((x) => getAssetClassComparisonStr(x))( S.Ord, ), (d) => d.collateralAsset, (utxo) => parseCollateralAssetDatumOrThrow(getInlineDatumOrThrow(utxo)), ); } type IAssetCreationDatumHelperReturnType = { newIAsset: IAssetContent; newReferencedIAsset: O.Option<IAssetContent>; }; export function iassetCreationDatumHelper( proposeAssetContent: ProposeAssetContent, referencedIAsset: O.Option<IAssetContent>, ): IAssetCreationDatumHelperReturnType { const newContent: IAssetContent = { assetName: proposeAssetContent.asset, collateralAssetsCount: 0n, debtMintingFeeRatio: proposeAssetContent.debtMintingFeeRatio, liquidationProcessingFeeRatio: proposeAssetContent.liquidationProcessingFeeRatio, stabilityPoolWithdrawalFeeRatio: proposeAssetContent.stabilityPoolWithdrawalFeeRatio, redemptionReimbursementRatio: proposeAssetContent.redemptionReimbursementRatio, redemptionProcessingFeeRatio: proposeAssetContent.redemptionProcessingFeeRatio, firstIAsset: true, nextIAsset: null, }; return F.pipe( referencedIAsset, O.match<IAssetContent, IAssetCreationDatumHelperReturnType>( () => ({ newIAsset: newContent, newReferencedIAsset: O.none, }), (referencedIA) => { if ( toText(toHex(proposeAssetContent.asset)) < toText(toHex(referencedIA.assetName)) ) { return { newIAsset: { ...newContent, firstIAsset: true, nextIAsset: referencedIA.assetName, }, newReferencedIAsset: O.some({ ...referencedIA, firstIAsset: false, }), }; } else { return { newIAsset: { ...newContent, firstIAsset: false, nextIAsset: referencedIA.nextIAsset, }, newReferencedIAsset: O.some({ ...referencedIA, nextIAsset: proposeAssetContent.asset, }), }; } }, ), ); } type CollateralAssetCreationDatumHelperReturnType = { newCollateralAsset: CollateralAssetContent; newReferencedCollateralAsset: O.Option<CollateralAssetContent>; }; export function collateralAssetCreationDatumHelper( addAssetContent: AddCollateralAsssetContent, referencedCollateralAsset: O.Option<CollateralAssetContent>, ): CollateralAssetCreationDatumHelperReturnType { const newContent: CollateralAssetContent = { iasset: addAssetContent.correspondingIAsset, collateralAsset: addAssetContent.collateralAsset, extraDecimals: addAssetContent.assetExtraDecimals, priceInfo: addAssetContent.assetPriceInfo, interestOracleNft: addAssetContent.interestOracleNft, redemptionRatio: addAssetContent.redemptionRatio, maintenanceRatio: addAssetContent.maintenanceRatio, liquidationRatio: addAssetContent.liquidationRatio, minCollateralAmt: addAssetContent.minCollateralAmt, firstCollateralAsset: true, nextCollateralAsset: null, }; return F.pipe( referencedCollateralAsset, O.match< CollateralAssetContent, CollateralAssetCreationDatumHelperReturnType >( () => ({ newCollateralAsset: newContent, newReferencedCollateralAsset: O.none, }), (referencedCA) => { if ( getAssetClassComparisonStr(addAssetContent.collateralAsset) < getAssetClassComparisonStr(referencedCA.collateralAsset) ) { return { newCollateralAsset: { ...newContent, firstCollateralAsset: true, nextCollateralAsset: referencedCA.collateralAsset, }, newReferencedCollateralAsset: O.some({ ...referencedCA, firstCollateralAsset: false, }), }; } else { return { newCollateralAsset: { ...newContent, firstCollateralAsset: false, nextCollateralAsset: referencedCA.nextCollateralAsset, }, newReferencedCollateralAsset: O.some({ ...referencedCA, nextCollateralAsset: addAssetContent.collateralAsset, }), }; } }, ), ); }