@indigo-labs/indigo-sdk
Version:
Indigo SDK for interacting with Indigo endpoints via lucid-evolution
407 lines (369 loc) • 10.3 kB
text/typescript
import {
fromHex,
fromText,
OutRef,
paymentCredentialOf,
unixTimeToSlot,
} from '@lucid-evolution/lucid';
import {
addrDetails,
createProposal,
createShardsChunks,
endProposal,
executeProposal,
fromSystemParamsAsset,
InterestOracleParams,
mergeShards,
openStakingPosition,
PriceOracleParams,
startInterestOracle,
SystemParams,
vote,
} from '../../src';
import { VoteOption } from '../../src/contracts/poll/types-poll-new';
import {
findAllPollShards,
findPollManager,
findRandomPollShard,
} from '../queries/poll-queries';
import { findStakingPosition } from '../queries/staking-queries';
import {
LucidContext,
runAndAwaitTx,
runAndAwaitTxBuilder,
selectWalletByAddress,
} from '../test-helpers';
import { findGov } from './governance-queries';
import { array as A } from 'fp-ts';
import { expect } from 'vitest';
import { findExecute } from '../queries/execute-queries';
import { CollateralAssetInfo } from '../endpoints/initialize';
import { startPriceOracleTx } from '../../src/contracts/price-oracle/transactions';
import { AssetClass } from '@3rd-eye-labs/cardano-offchain-common';
import {
findAllCollateralAssetsOfIAsset,
findIAsset,
} from '../queries/iasset-queries';
import { Rational, rationalFromInt } from '../../src/types/rational';
export async function runVote(
pollId: bigint,
option: VoteOption,
sysParams: SystemParams,
context: LucidContext,
): Promise<void> {
const [pkh, _] = await addrDetails(context.lucid);
const stakingPosOref = await findStakingPosition(
context.lucid,
sysParams.validatorHashes.stakingHash,
fromSystemParamsAsset(sysParams.stakingParams.stakingToken),
pkh.hash,
);
const pollShard = await findRandomPollShard(
context.lucid,
sysParams.validatorHashes.pollShardHash,
fromSystemParamsAsset(sysParams.pollShardParams.pollToken),
pollId,
);
await runAndAwaitTx(
context.lucid,
vote(
option,
pollShard.utxo,
stakingPosOref.utxo,
sysParams,
context.lucid,
context.emulator.slot,
),
);
}
export async function runCreateAllShards(
pollId: bigint,
sysParams: SystemParams,
context: LucidContext,
): Promise<void> {
const govUtxo = await findGov(
context.lucid,
sysParams.validatorHashes.govHash,
fromSystemParamsAsset(sysParams.govParams.govNFT),
);
for (
let i = 0;
i < Math.ceil(Number(govUtxo.datum.protocolParams.totalShards) / 2);
i++
) {
const pollUtxo = await findPollManager(
context.lucid,
sysParams.validatorHashes.pollManagerHash,
fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
pollId,
);
await runAndAwaitTx(
context.lucid,
createShardsChunks(
2n,
pollUtxo.utxo,
sysParams,
context.emulator.slot,
context.lucid,
),
);
}
}
export async function runMergeAllShards(
pollId: bigint,
sysParams: SystemParams,
context: LucidContext,
): Promise<void> {
const govUtxo = await findGov(
context.lucid,
sysParams.validatorHashes.govHash,
fromSystemParamsAsset(sysParams.govParams.govNFT),
);
for (
let i = 0;
i < Math.ceil(Number(govUtxo.datum.protocolParams.totalShards) / 2);
i++
) {
const pollUtxo = await findPollManager(
context.lucid,
sysParams.validatorHashes.pollManagerHash,
fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
pollId,
);
const allPollShards = await findAllPollShards(
context.lucid,
sysParams.validatorHashes.pollShardHash,
fromSystemParamsAsset(sysParams.pollShardParams.pollToken),
pollUtxo.datum.pollId,
);
await runAndAwaitTx(
context.lucid,
mergeShards(
pollUtxo.utxo,
A.takeLeft(2)(allPollShards).map((u) => u.utxo),
sysParams,
context.lucid,
context.emulator.slot,
),
);
}
}
export async function runEndProposal(
pollId: bigint,
sysParams: SystemParams,
context: LucidContext,
): Promise<void> {
const pollUtxo = await findPollManager(
context.lucid,
sysParams.validatorHashes.pollManagerHash,
fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
pollId,
);
const govUtxo = await findGov(
context.lucid,
sysParams.validatorHashes.govHash,
fromSystemParamsAsset(sysParams.govParams.govNFT),
);
await runAndAwaitTx(
context.lucid,
endProposal(
pollUtxo.utxo,
govUtxo.utxo,
sysParams,
context.lucid,
context.emulator.slot,
),
);
}
export async function waitForVotingEnd(
pollId: bigint,
sysParams: SystemParams,
context: LucidContext,
): Promise<void> {
const pollUtxo = await findPollManager(
context.lucid,
sysParams.validatorHashes.pollManagerHash,
fromSystemParamsAsset(sysParams.pollManagerParams.pollToken),
pollId,
);
const targetSlot = unixTimeToSlot(
context.lucid.config().network!,
Number(pollUtxo.datum.votingEndTime),
);
if (targetSlot > context.emulator.slot) {
expect(targetSlot).toBeGreaterThan(context.emulator.slot);
context.emulator.awaitSlot(targetSlot - context.emulator.slot + 1);
}
}
export async function runExecuteProposal(
pollId: bigint,
treasuryWithdrawalOref: OutRef | null,
allIAssetOrefs: OutRef[] | null,
iAssetOref: OutRef | null,
allCollateralAssetsOrefsOfIAsset: OutRef[] | null,
collateralAssetOref: OutRef | null,
stableswapPoolOrCdpCreatorOref: OutRef | null,
sysParams: SystemParams,
context: LucidContext,
): Promise<void> {
const executeUtxo = await findExecute(
context.lucid,
sysParams.validatorHashes.executeHash,
fromSystemParamsAsset(sysParams.executeParams.upgradeToken),
pollId,
);
await runAndAwaitTx(
context.lucid,
executeProposal(
executeUtxo.utxo,
(
await findGov(
context.lucid,
sysParams.validatorHashes.govHash,
fromSystemParamsAsset(sysParams.govParams.govNFT),
)
).utxo,
treasuryWithdrawalOref,
allIAssetOrefs,
iAssetOref,
allCollateralAssetsOrefsOfIAsset,
collateralAssetOref,
stableswapPoolOrCdpCreatorOref,
sysParams,
context.lucid,
context.emulator.slot,
),
);
}
export async function processSuccessfulProposal(
pollId: bigint,
treasuryWithdrawalOref: OutRef | null,
allIAssetOrefs: OutRef[] | null,
iAssetOref: OutRef | null,
allCollateralAssetsOrefsOfIAsset: OutRef[] | null,
collateralAssetOref: OutRef | null,
stableswapPoolOrCdpCreatorOref: OutRef | null,
sysParams: SystemParams,
context: LucidContext,
createStakingPos: boolean = true,
): Promise<void> {
await runCreateAllShards(pollId, sysParams, context);
if (createStakingPos) {
await runAndAwaitTx(
context.lucid,
openStakingPosition(100_000_000_000n, sysParams, context.lucid),
);
}
await runVote(pollId, 'Yes', sysParams, context);
await waitForVotingEnd(pollId, sysParams, context);
await runMergeAllShards(pollId, sysParams, context);
await runEndProposal(pollId, sysParams, context);
await runExecuteProposal(
pollId,
treasuryWithdrawalOref,
allIAssetOrefs,
iAssetOref,
allCollateralAssetsOrefsOfIAsset,
collateralAssetOref,
stableswapPoolOrCdpCreatorOref,
sysParams,
context,
);
}
export async function whitelistCollateralAsset(
context: LucidContext,
sysParams: SystemParams,
iassetAscii: string,
newCollateralAsset: AssetClass,
initialPrice: Rational,
initialInterest: bigint,
createStakingPos: boolean,
): Promise<CollateralAssetInfo> {
const prevAddr = await context.lucid.wallet().address();
context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
const interestOracleParams: InterestOracleParams = {
biasTime: 120_000n,
owner: paymentCredentialOf(context.users.admin.address).hash,
};
const [startInterestTx, interestOracleNft] = await startInterestOracle(
0n,
initialInterest,
0n,
interestOracleParams,
context.lucid,
);
await runAndAwaitTxBuilder(context.lucid, startInterestTx);
const oracleParams: PriceOracleParams = {
biasTime: 120_000n,
expirationPeriod: 1_800_000n,
owner: paymentCredentialOf(context.users.admin.address).hash,
};
const [priceOracleTx, priceOranceNft] = await startPriceOracleTx(
context.lucid,
'COLLATERAL_ORACLE',
initialPrice,
oracleParams,
context.emulator.slot,
);
await runAndAwaitTxBuilder(context.lucid, priceOracleTx);
const [tx, pollId] = await createProposal(
{
AddCollateralAsset: {
correspondingIAsset: fromHex(fromText(iassetAscii)),
collateralAsset: newCollateralAsset,
assetExtraDecimals: 0n,
assetPriceInfo: { OracleNft: priceOranceNft },
interestOracleNft: interestOracleNft,
redemptionRatio: rationalFromInt(2n),
maintenanceRatio: { numerator: 15n, denominator: 10n },
liquidationRatio: { numerator: 12n, denominator: 10n },
minCollateralAmt: 1_000_000n,
},
},
null,
sysParams,
context.lucid,
context.emulator.slot,
(
await findGov(
context.lucid,
sysParams.validatorHashes.govHash,
fromSystemParamsAsset(sysParams.govParams.govNFT),
)
).utxo,
[],
);
await runAndAwaitTxBuilder(context.lucid, tx);
const iassetOutput = await findIAsset(
context.lucid,
sysParams.validatorHashes.iassetHash,
fromSystemParamsAsset(sysParams.executeParams.iAssetToken),
iassetAscii,
);
await processSuccessfulProposal(
pollId,
null,
null,
iassetOutput.utxo,
(
await findAllCollateralAssetsOfIAsset(
context.lucid,
sysParams.validatorHashes.iassetHash,
fromSystemParamsAsset(sysParams.executeParams.collateralAssetToken),
fromHex(fromText(iassetAscii)),
)
).map((o) => o.utxo),
null,
null,
sysParams,
context,
createStakingPos,
);
selectWalletByAddress(context, prevAddr);
return {
collateralAsset: newCollateralAsset,
interestOracleNft: interestOracleNft,
oracleParams: oracleParams,
interestOracleParams,
};
}