Skip to content

Commit

Permalink
refactor(vault): liquidate with offerArgs
Browse files Browse the repository at this point in the history
* turn off unneeded tracing
* pass `debt` to liquidation as an offerArg
* add trace info in liquidation
  • Loading branch information
dtribble committed Apr 13, 2022
1 parent 4e9353d commit de5daf4
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 69 deletions.
130 changes: 65 additions & 65 deletions packages/run-protocol/src/vaultFactory/liquidateMinimum.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Far } from '@endo/marshal';
import { makeDefaultLiquidationStrategy } from './liquidation.js';
import { makeTracer } from '../makeTracer.js';

const trace = makeTracer('LM');
const trace = makeTracer('LiqMin');

/**
* This contract liquidates the minimum amount of vault's collateral necessary
Expand All @@ -25,74 +25,75 @@ const start = async zcf => {
const { amm } = zcf.getTerms();

/**
* @param {Amount<'nat'>} runDebt
* @param {ZCFSeat} debtorSeat
* @param {{ debt: Amount<'nat'> }} options
*/
const makeDebtorHook = runDebt => {
const runBrand = runDebt.brand;
return async debtorSeat => {
const {
give: { In: amountIn },
} = debtorSeat.getProposal();
const inBefore = debtorSeat.getAmountAllocated('In');

const swapInvitation = E(amm).makeSwapOutInvitation();
const liqProposal = harden({
give: { In: amountIn },
want: { Out: runDebt },
const debtorHook = async (debtorSeat, { debt }) => {
const debtBrand = debt.brand;
const {
give: { In: amountIn },
} = debtorSeat.getProposal();
const swapInvitation = E(amm).makeSwapOutInvitation();
const liqProposal = harden({
give: { In: amountIn },
want: { Out: debt },
});
trace(`OFFER TO DEBT: `, debt, amountIn);
const { deposited, userSeatPromise: liqSeat } = await offerTo(
zcf,
swapInvitation,
undefined, // The keywords were mapped already
liqProposal,
debtorSeat,
);

// Three (!) awaits coming here. We can't use Promise.all because
// offerTo() can return before getOfferResult() is valid, and we can't
// check whether swapIn liquidated assets until getOfferResult() returns.
// Of course, we also can't exit the seat until one or the other
// liquidation takes place.
const [offerResult, amounts, _deposited] = await Promise.all([
E(liqSeat).getOfferResult(),
E(liqSeat).getCurrentAllocation(),
deposited,
]);
trace('offerResult', offerResult, amounts);

// if swapOut failed to make the trade, we'll sell it all
const sellAllIfUnsold = async () => {
const unsold = debtorSeat.getAmountAllocated('In');
// We cannot easily directly check that the `offerTo` succeeded, so we
// check that amotun unsold is not what we started with.
if (!AmountMath.isEqual(amountIn, unsold)) {
trace('Changed', { inBefore: amountIn, unsold });
return;
}

trace('liquidating all collateral because swapIn did not succeed');
const strategy = makeDefaultLiquidationStrategy(amm);
const { deposited: sellAllDeposited, userSeatPromise: sellAllSeat } =
await offerTo(
zcf,
strategy.makeInvitation(debt),
undefined, // The keywords were mapped already
strategy.makeProposal(amountIn, AmountMath.makeEmpty(debtBrand)),
debtorSeat,
);
// await sellAllDeposited, but don't need the value
await Promise.all([
E(sellAllSeat).getOfferResult(),
sellAllDeposited,
]).catch(sellAllError => {
throw Error(`Unable to liquidate ${sellAllError}`);
});
trace(`OFFER TO DEBT: `, runDebt.value);

const { deposited, userSeatPromise: liqSeat } = await offerTo(
zcf,
swapInvitation,
undefined, // The keywords were mapped already
liqProposal,
debtorSeat,
);

// Three (!) awaits coming here. We can't use Promise.all because
// offerTo() can return before getOfferResult() is valid, and we can't
// check whether swapIn liquidated assets until getOfferResult() returns.
// Of course, we also can't exit the seat until one or the other
// liquidation takes place.
await deposited;
await E(liqSeat).getOfferResult();

// if swapOut failed to make the trade, we'll sell it all
const sellAllIfUnsold = async () => {
if (
!AmountMath.isEqual(inBefore, debtorSeat.getAmountAllocated('In'))
) {
return;
}

trace('liquidating all collateral because swapIn did not succeed');
const strategy = makeDefaultLiquidationStrategy(amm);
const { deposited: sellAllDeposited, userSeatPromise: sellAllSeat } =
await offerTo(
zcf,
strategy.makeInvitation(runDebt),
undefined, // The keywords were mapped already
strategy.makeProposal(amountIn, AmountMath.makeEmpty(runBrand)),
debtorSeat,
);
// await sellAllDeposited, but don't need the value
await Promise.all([
E(sellAllSeat).getOfferResult(),
sellAllDeposited,
]).catch(sellAllError => {
throw Error(`Unable to liquidate ${sellAllError}`);
});
};
await sellAllIfUnsold();

debtorSeat.exit();
};
await sellAllIfUnsold();
trace(`Liq results`, debt, debtorSeat.getAmountAllocated('RUN', debtBrand));
debtorSeat.exit();
};

const creatorFacet = Far('debtorInvitationCreator', {
makeDebtorInvitation: runDebt =>
zcf.makeInvitation(makeDebtorHook(runDebt), 'Liquidate'),
makeDebtorInvitation: () => zcf.makeInvitation(debtorHook, 'Liquidate'),
});

return harden({ creatorFacet });
Expand All @@ -104,8 +105,7 @@ const start = async zcf => {
* @param {LiquidationContract['creatorFacet']} creatorFacet
*/
const makeLiquidationStrategy = creatorFacet => {
const makeInvitation = async runDebt =>
E(creatorFacet).makeDebtorInvitation(runDebt);
const makeInvitation = () => E(creatorFacet).makeDebtorInvitation();

const keywordMapping = () =>
harden({
Expand Down
3 changes: 2 additions & 1 deletion packages/run-protocol/src/vaultFactory/liquidation.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,14 @@ const liquidate = async (
collateralBrand,
);

// XXX problems with upgrade
const { deposited, userSeatPromise: liqSeat } = await offerTo(
zcf,
strategy.makeInvitation(debt),
strategy.keywordMapping(),
strategy.makeProposal(collateralToSell, debt),
vaultZcfSeat,
vaultZcfSeat,
harden({ debt }),
);
trace(` offeredTo`, collateralToSell, debt);

Expand Down
2 changes: 1 addition & 1 deletion packages/run-protocol/src/vaultFactory/vault.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { addSubtract, assertOnlyKeys, stageDelta } from '../contractSupport.js';

const { details: X, quote: q } = assert;

const trace = makeTracer('IV');
const trace = makeTracer('IV', false);

/**
* @file This has most of the logic for a Vault, to borrow RUN against collateral.
Expand Down
7 changes: 6 additions & 1 deletion packages/run-protocol/src/vaultFactory/vaultFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,12 @@ export const start = async (zcf, privateArgs) => {
const { creatorFacet: liquidationFacet } = await E(zoe).startInstance(
liquidationInstall,
harden({ RUN: debtIssuer, Collateral: collateralIssuer }),
harden({ amm: ammPublicFacet }),
harden({
amm: ammPublicFacet,
priceAuthority,
timerService,
debtBrand,
}),
);
const liquidationStrategy = makeLiquidationStrategy(liquidationFacet);

Expand Down
3 changes: 2 additions & 1 deletion packages/run-protocol/src/vaultFactory/vaultManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { chargeInterest } from '../interest.js';

const { details: X, quote: q } = assert;

const trace = makeTracer('VM');
const trace = makeTracer('VM', false);

/**
* @typedef {{
Expand Down Expand Up @@ -157,6 +157,7 @@ export const makeVaultManager = (
liquidationInProgress = false;
// XXX should notify interested parties
console.error('liquidateAndRemove failed with', e);
throw e;
});
};

Expand Down

0 comments on commit de5daf4

Please sign in to comment.