Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: multipoolAutoswap should throw seat.fail() when it can't comply #2337

Merged
merged 1 commit into from
Feb 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/zoe/src/contracts/loan/liquidate.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const doLiquidation = async (
lenderSeat.fail(err);
collateralSeat.fail(err);
zcf.shutdownWithFailure(err);
throw err;
};

const offerResultP = E(autoswapUserSeat).getOfferResult();
Expand Down
4 changes: 2 additions & 2 deletions packages/zoe/src/contracts/multipoolAutoswap/swap.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ export const makeMakeSwapInvitation = (

const brandInAmountMath = getPool(brandIn).getAmountMath();
if (!brandInAmountMath.isGTE(offeredAmountIn, amountIn)) {
seat.fail();
return `offeredAmountIn ${offeredAmountIn} is insufficient to buy amountOut ${amountOut}`;
const reason = `offeredAmountIn ${offeredAmountIn} is insufficient to buy amountOut ${amountOut}`;
throw seat.fail(Error(reason));
}

trade(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,10 @@ test('test with malfunctioning autoswap', async t => {
makeSwapInInvitation: () => zcf.makeInvitation(swapHandler, 'swap'),
});

await doLiquidation(zcf, collateralSeat, autoswapPublicFacetP, lenderSeat);
await t.throwsAsync(
() => doLiquidation(zcf, collateralSeat, autoswapPublicFacetP, lenderSeat),
{ message: 'Pool not initialized' },
);

// Ensure collateralSeat exited
t.truthy(collateralSeat.hasExited());
Expand Down
95 changes: 95 additions & 0 deletions packages/zoe/test/unitTests/contracts/test-multipoolAutoswap.js
Original file line number Diff line number Diff line change
Expand Up @@ -1655,3 +1655,98 @@ test('multipoolAutoSwap jig - remove all liquidity', async t => {
);
moolaPoolState = updatePoolState(moolaPoolState, liqExpected);
});

test('multipoolAutoSwap jig - insufficient', async t => {
const { moolaR, moola } = setup();
const zoe = makeZoe(fakeVatAdmin);

// Pack the contract.
const bundle = await bundleSource(multipoolAutoswapRoot);
const installation = await zoe.install(bundle);

// Set up central token
const centralR = makeIssuerKit('central');
const centralTokens = centralR.amountMath.make;

// set up purses
const centralPayment = centralR.mint.mintPayment(centralTokens(30000));
const centralPurse = centralR.issuer.makeEmptyPurse();
await centralPurse.deposit(centralPayment);
const moolaPurse = moolaR.issuer.makeEmptyPurse();
moolaPurse.deposit(moolaR.mint.mintPayment(moola(20000)));

const startRecord = await zoe.startInstance(
installation,
harden({ Central: centralR.issuer }),
);
/** @type {MultipoolAutoswapPublicFacet} */
const { publicFacet } = startRecord;
const moolaLiquidityIssuer = await E(publicFacet).addPool(
moolaR.issuer,
'Moola',
);
const moolaLiquidityAmountMath = await makeLocalAmountMath(
moolaLiquidityIssuer,
);

const moolaLiquidity = moolaLiquidityAmountMath.make;
const mIssuerKeywordRecord = {
Secondary: moolaR.issuer,
Liquidity: moolaLiquidityIssuer,
};
const purses = [
moolaPurse,
moolaLiquidityIssuer.makeEmptyPurse(),
centralPurse,
];
const alice = await makeTrader(purses, zoe, publicFacet, centralR.issuer);

let mPoolState = {
c: 0,
s: 0,
l: 0,
k: 0,
};
const initMoolaLiquidityDetails = {
cAmount: centralTokens(10000),
sAmount: moola(10000),
lAmount: moolaLiquidity(10000),
};
const initMoolaLiquidityExpected = {
c: 10000,
s: 10000,
l: 10000,
k: 100000000,
payoutC: 0,
payoutS: 0,
payoutL: 10000,
};
await alice.initLiquidityAndCheck(
t,
mPoolState,
initMoolaLiquidityDetails,
initMoolaLiquidityExpected,
mIssuerKeywordRecord,
);
mPoolState = updatePoolState(mPoolState, initMoolaLiquidityExpected);

// trade for central specifying 300 output: moola price 311
const gain = 300;
const mPrice = priceFromTargetOutput(gain, mPoolState.c, mPoolState.s, 30);
t.is(mPrice, 311);

// provide insufficient moola; trade fails
const seat = await alice.offerAndTrade(
centralTokens(gain),
moola(200),
false,
);
await t.throwsAsync(
() => seat.getOfferResult(),
{ message: / is insufficient to buy amountOut / },
`shouldn't have been able to trade`,
);
const { In: refund, Out: payout } = await seat.getPayouts();
t.deepEqual(await moolaR.issuer.getAmountOf(refund), moola(200));
t.deepEqual(await centralR.issuer.getAmountOf(payout), centralTokens(0));
});