Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit 728d695
Author: anilhelvaci <[email protected]>
Date:   Wed Jan 31 14:28:14 2024 +0300

    chore(liquidationVisibility): uncomment post auction assertion in `liq-result-scenario-1`

commit dd3fbdb
Author: anilhelvaci <[email protected]>
Date:   Wed Jan 31 14:25:22 2024 +0300

    fix(liquidationVisibility): lint fix

commit 6920d1a
Author: anilhelvaci <[email protected]>
Date:   Wed Jan 31 14:22:28 2024 +0300

    fix(liquidationVisibility): explain Promise.allSettled

commit 732e1d7
Author: anilhelvaci <[email protected]>
Date:   Wed Jan 31 11:37:45 2024 +0300

    feat(liquidationVisibility): handle errors that might arise from other vats

commit 683f56d
Author: anilhelvaci <[email protected]>
Date:   Tue Jan 30 14:31:13 2024 +0300

    feat(liquidationVisibility): add LiquidationVisibilityWriters to improve readability, fetch schedule during the auction itself

commit 4c45f2a
Author: anilhelvaci <[email protected]>
Date:   Tue Jan 30 10:30:02 2024 +0300

    fix(liquidationVisibility): add pattern matcher to `getVaultState`
  • Loading branch information
Jorge-Lopes authored and anilhelvaci committed Feb 16, 2024
1 parent fcaf76d commit a26eec2
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 89 deletions.
14 changes: 8 additions & 6 deletions packages/inter-protocol/src/vaultFactory/liquidation.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ const trace = makeTracer('LIQ');
/** @typedef {import('@agoric/time').CancelToken} CancelToken */
/** @typedef {import('@agoric/time').RelativeTimeRecord} RelativeTimeRecord */

/**
* @typedef {MapStore<
* Vault,
* { collateralAmount: Amount<'nat'>; debtAmount: Amount<'nat'> }
* >} VaultData
*/

const makeCancelToken = makeCancelTokenMaker('liq');

/**
Expand Down Expand Up @@ -269,12 +276,7 @@ export const getLiquidatableVaults = (
const vaultsToLiquidate = prioritizedVaults.removeVaultsBelow(
collateralizationDetails,
);
/**
* @type {MapStore<
* Vault,
* { collateralAmount: Amount<'nat'>; debtAmount: Amount<'nat'> }
* >}
*/
/** @type {VaultData} */
const vaultData = makeScalarMapStore();

const { zcfSeat: liqSeat } = zcf.makeEmptySeatKit();
Expand Down
25 changes: 25 additions & 0 deletions packages/inter-protocol/src/vaultFactory/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
*
* @typedef {import('@agoric/time').Timestamp} Timestamp
*
* @typedef {import('@agoric/time').TimestampRecord} TimestampRecord
*
* @typedef {import('@agoric/time').RelativeTime} RelativeTime
*/

Expand Down Expand Up @@ -142,3 +144,26 @@
*/

/** @typedef {{ key: 'governedParams' | { collateralBrand: Brand } }} VaultFactoryParamPath */

/**
* @typedef {{
* plan: import('./proceeds.js').DistributionPlan;
* vaultsInPlan: Array;
* }} PostAuctionParams
*
* @typedef {{
* plan: import('./proceeds.js').DistributionPlan;
* totalCollateral: Amount<'nat'>;
* totalDebt: Amount<'nat'>;
* auctionSchedule: import('../auction/scheduler.js').FullSchedule;
* }} AuctionResultsParams
*/

/**
* @typedef {import('./liquidation.js').VaultData} VaultData
*
* @typedef {object} LiquidationVisibilityWriters
* @property {(vaultData: VaultData) => Promise<void>} writePreAuction
* @property {(postAuctionParams: PostAuctionParams) => Promise<void>} writePostAuction
* @property {(auctionResultParams: AuctionResultsParams) => Promise<void>} writeAuctionResults
*/
4 changes: 3 additions & 1 deletion packages/inter-protocol/src/vaultFactory/vault.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ export const VaultI = M.interface('Vault', {
getCurrentDebt: M.call().returns(AmountShape),
getNormalizedDebt: M.call().returns(AmountShape),
getVaultSeat: M.call().returns(SeatShape),
getVaultState: M.call().returns(M.any()),
getVaultState: M.call().returns(
harden({ idInManager: M.string(), phase: M.string() }),
),
initVaultKit: M.call(SeatShape, StorageNodeShape).returns(M.promise()),
liquidated: M.call().returns(undefined),
liquidating: M.call().returns(undefined),
Expand Down
201 changes: 151 additions & 50 deletions packages/inter-protocol/src/vaultFactory/vaultManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import {
TopicsRecordShape,
} from '@agoric/zoe/src/contractSupport/index.js';
import { PriceQuoteShape, SeatShape } from '@agoric/zoe/src/typeGuards.js';
import { E } from '@endo/eventual-send';
import { E, Far } from '@endo/far';
import { TimestampShape } from '@agoric/time';
import { AuctionPFShape } from '../auction/auctioneer.js';
import {
Expand Down Expand Up @@ -233,6 +233,9 @@ export const watchQuoteNotifier = async (notifierP, watcher, ...args) => {
* auctionResultRecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit<AuctionResultState>;
* }} LiquidationRecorderKits
*/

/** @typedef {import('./liquidation.js').VaultData} VaultData */

// any b/c will be filled after start()
const collateralEphemera = makeEphemeraProvider(() => /** @type {any} */ ({}));

Expand Down Expand Up @@ -684,7 +687,107 @@ export const prepareVaultManagerKit = (
},

/**
* @param {{ absValue: any }} timestamp
* @param {TimestampRecord} timestamp
* @returns {Promise<LiquidationVisibilityWriters>}
*/
async makeLiquidationVisibilityWriters(timestamp) {
const liquidationRecorderKits =
await this.facets.helper.makeLiquidationRecorderKits(timestamp);

/** @param {VaultData} vaultData */
const writePreAuction = vaultData => {
/** @type PreAuctionState */
const preAuctionState = [...vaultData.entries()].map(
([vault, data]) => [
`vault${vault.getVaultState().idInManager}`,
{ ...data },
],
);

return E(
liquidationRecorderKits.preAuctionRecorderKit.recorder,
).writeFinal(preAuctionState);
};

/**
* @param {PostAuctionParams} params
* @returns {Promise<void>}
*/
const writePostAuction = ({ plan, vaultsInPlan }) => {
/** @type PostAuctionState */
const postAuctionState = plan.transfersToVault.map(
([id, transfer]) => [
`vault${vaultsInPlan[id].getVaultState().idInManager}`,
{
...transfer,
phase: vaultsInPlan[id].getVaultState().phase,
},
],
);
return E(
liquidationRecorderKits.postAuctionRecorderKit.recorder,
).writeFinal(postAuctionState);
};

/** @param {AuctionResultsParams} params */
const writeAuctionResults = ({
plan,
totalCollateral,
totalDebt,
auctionSchedule,
}) => {
/** @type AuctionResultState */
const auctionResultState = {
collateralOffered: totalCollateral,
istTarget: totalDebt,
collateralForReserve: plan.collateralForReserve,
shortfallToReserve: plan.shortfallToReserve,
mintedProceeds: plan.mintedProceeds,
collateralSold: plan.collateralSold,
collateralRemaining: plan.collatRemaining,
// @ts-expect-error
// eslint-disable-next-line @endo/no-optional-chaining
endTime: auctionSchedule?.liveAuctionSchedule.endTime,
};
return E(
liquidationRecorderKits.auctionResultRecorderKit.recorder,
).writeFinal(auctionResultState);
};

return Far('Liquidation Visibility Writers', {
writePreAuction,
writePostAuction,
writeAuctionResults,
});
},

/**
* This method checks if liquidationVisibilityWriters is undefined or
* not in case of a rejected promise when creating the writers. If
* liquidationVisibilityWriters is undefined it silently notifies the
* console. Otherwise, it goes on with the writing.
*
* @param {LiquidationVisibilityWriters} liquidationVisibilityWriters
* @param {[string, object][]} writes
*/
async writeLiqVisibility(liquidationVisibilityWriters, writes) {
console.log('WRITES', writes);
if (!liquidationVisibilityWriters) {
trace(
'writeLiqVisibility',
`Error: liquidationVisibilityWriters is ${liquidationVisibilityWriters}`,
);
return;
}

for (const [methodName, params] of writes) {
trace('DEBUG', methodName, params);
void liquidationVisibilityWriters[methodName](params);
}
},

/**
* @param {TimestampRecord} timestamp
* @returns {Promise<LiquidationRecorderKits>}
*/
async makeLiquidationRecorderKits(timestamp) {
Expand Down Expand Up @@ -1193,7 +1296,7 @@ export const prepareVaultManagerKit = (
},
/**
* @param {ERef<AuctioneerPublicFacet>} auctionPF
* @param {{ absValue: bigint }} timestamp
* @param {TimestampRecord} timestamp
*/
async liquidateVaults(auctionPF, timestamp) {
const { state, facets } = this;
Expand Down Expand Up @@ -1258,6 +1361,7 @@ export const prepareVaultManagerKit = (
liquidatingVaults.getSize(),
totalCollateral,
);
const schedulesP = E(auctionPF).getSchedules();

helper.markLiquidating(totalDebt, totalCollateral);
void helper.writeMetrics();
Expand All @@ -1276,31 +1380,35 @@ export const prepareVaultManagerKit = (
),
);

const [{ userSeatPromise, deposited }, liquidationRecorderKits] =
await Promise.all([
// helper.makeLiquidationVisibilityWriters and schedulesP depends on others vats,
// so we switched from Promise.all to Promise.allSettled because if one of those vats fail
// we don't want those failures to prevent liquidation process from going forward.
// We don't handle the case where 'makeDeposit' rejects as liquidation depends on
// 'makeDeposit' being fulfilled.
await null;
const [
{ userSeatPromise, deposited },
liquidationVisibilityWriters,
auctionSchedule,
] = (
await Promise.allSettled([
makeDeposit,
helper.makeLiquidationRecorderKits(timestamp),
]);

/** @type PreAuctionState */
const preAuctionState = [...vaultData.entries()].map(
([vault, data]) => [
`vault${vault.getVaultState().idInManager}`,
{ ...data },
],
);
helper.makeLiquidationVisibilityWriters(timestamp),
schedulesP,
])
)
.filter(result => result.status === 'fulfilled')
// @ts-expect-error
.map(result => result.value);

void helper.writeLiqVisibility(liquidationVisibilityWriters, [
['writePreAuction', vaultData],
]);

// This is expected to wait for the duration of the auction, which
// is controlled by the auction parameters startFrequency, clockStep,
// and the difference between startingRate and lowestRate.
const [auctionSchedule, proceeds] = await Promise.all([
E(auctionPF).getSchedules(),
deposited,
userSeatPromise,
E(
liquidationRecorderKits.preAuctionRecorderKit.recorder,
).writeFinal(preAuctionState),
]);
const [proceeds] = await Promise.all([deposited, userSeatPromise]);

const { storedCollateralQuote } = collateralEphemera(
this.state.collateralBrand,
Expand Down Expand Up @@ -1328,34 +1436,27 @@ export const prepareVaultManagerKit = (
vaultsInPlan,
});

/** @type AuctionResultState */
const auctionResultState = {
collateralOffered: totalCollateral,
istTarget: totalDebt,
collateralForReserve: plan.collateralForReserve,
shortfallToReserve: plan.shortfallToReserve,
mintedProceeds: plan.mintedProceeds,
collateralSold: plan.collateralSold,
collateralRemaining: plan.collatRemaining,
endTime: auctionSchedule.liveAuctionSchedule?.endTime,
};
void E(
liquidationRecorderKits.auctionResultRecorderKit.recorder,
).writeFinal(auctionResultState);

/** @type PostAuctionState */
const postAuctionState = plan.transfersToVault.map(
([id, transfer]) => [
`vault${vaultsInPlan[id].getVaultState().idInManager}`,
{
...transfer,
phase: vaultsInPlan[id].getVaultState().phase,
},
],
void helper.writeLiqVisibility(
liquidationVisibilityWriters,
harden([
[
'writeAuctionResults',
{
plan,
totalCollateral,
totalDebt,
auctionSchedule,
},
],
[
'writePostAuction',
{
plan,
vaultsInPlan,
},
],
]),
);
void E(
liquidationRecorderKits.postAuctionRecorderKit.recorder,
).writeFinal(postAuctionState);
} catch (err) {
console.error('🚨 Error distributing proceeds:', err);
}
Expand Down
Loading

0 comments on commit a26eec2

Please sign in to comment.