@indigo-labs/indigo-sdk
Version:
Indigo SDK for interacting with Indigo endpoints via lucid-evolution
169 lines (142 loc) • 4.12 kB
text/typescript
import {
negateAssets,
noAdaValue,
} from '@3rd-eye-labs/cardano-offchain-common';
import {
addAssets,
Assets,
credentialToAddress,
getAddressDetails,
LucidEvolution,
paymentCredentialOf,
UTxO,
} from '@lucid-evolution/lucid';
import { array as A, function as F } from 'fp-ts';
import { zipWith } from 'fp-ts/lib/Array';
import { runAndAwaitTxBuilder } from '../test-helpers';
/**
* In case passing in address with stake credential, the non stake credential address
* is used as well for collecting inputs but cannot increase its value.
*/
export async function getValueChangeAtAddressAfterAction<T>(
lucid: LucidEvolution,
address: string,
action: () => Promise<T>,
): Promise<[T, Assets]> {
const hasStakeCred = getAddressDetails(address).stakeCredential != null;
const valBefore = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
addAssets(acc, utxo.assets),
)(await lucid.utxosAt(address));
const [res, nonStakeCredValChange] = hasStakeCred
? await getValueChangeAtAddressAfterAction(
lucid,
credentialToAddress(
lucid.config().network!,
paymentCredentialOf(address),
),
action,
)
: [await action(), {}];
if (
hasStakeCred &&
!Object.entries(nonStakeCredValChange).every(([_, amt]) => amt <= 0n)
) {
throw new Error("Can't add value to the address without stake credential");
}
const valAfter = A.reduce<UTxO, Assets>({}, (acc, utxo) =>
addAssets(acc, utxo.assets),
)(await lucid.utxosAt(address));
return [
res,
addAssets(valAfter, negateAssets(valBefore), nonStakeCredValChange),
];
}
export async function getValueChangeAtAddressesAfterAction<T>(
lucid: LucidEvolution,
addresses: string[],
action: () => Promise<T>,
): Promise<[T, Assets[]]> {
const valsBefore = [];
for (const address of addresses) {
const utxos = await lucid.utxosAt(address);
valsBefore.push(
F.pipe(
utxos,
A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets)),
),
);
}
const res = await action();
const valsAfter = [];
for (const address of addresses) {
const utxos = await lucid.utxosAt(address);
valsAfter.push(
F.pipe(
utxos,
A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets)),
),
);
}
return [
res,
zipWith(valsBefore, valsAfter, (valBefore, valAfter) =>
addAssets(valAfter, negateAssets(valBefore)),
),
];
}
export async function getNewUtxosAtAddressAfterAction<T>(
lucid: LucidEvolution,
address: string,
action: () => Promise<T>,
): Promise<[T, UTxO[]]> {
const utxosBefore = await lucid.utxosAt(address);
const res = await action();
const utxosAfter = await lucid.utxosAt(address);
return [
res,
utxosAfter.filter(
(utxo) =>
utxosBefore.filter(
(oldUtxo) =>
utxo.txHash === oldUtxo.txHash &&
utxo.outputIndex === oldUtxo.outputIndex,
).length === 0,
),
];
}
export async function totalValueAtAddress(
lucid: LucidEvolution,
addr: string,
): Promise<Assets> {
const utxos = await lucid.utxosAt(addr);
return F.pipe(
utxos,
A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets)),
);
}
export async function sendValueTo(
destinationAddr: string,
value: Assets,
lucid: LucidEvolution,
): Promise<void> {
await runAndAwaitTxBuilder(
lucid,
lucid.newTx().pay.ToAddress(destinationAddr, value),
);
}
/**
* For all the non-ADA assets in current wallet, create a separate UTXo with each of them.
*/
export async function fragmentWallet(lucid: LucidEvolution): Promise<void> {
const currentAddr = await lucid.wallet().address();
const totalVal = await totalValueAtAddress(lucid, currentAddr);
const otherAssets = Object.keys(noAdaValue(totalVal));
if (otherAssets.length === 0) return;
const tx = lucid.newTx();
for (const asset of otherAssets) {
tx.pay.ToAddress(currentAddr, {
[asset]: totalVal[asset],
});
}
await runAndAwaitTxBuilder(lucid, tx);
}