Skip to content

Commit

Permalink
bug: improve handling of orders that are consummated immediately
Browse files Browse the repository at this point in the history
in the wallet, only subscribe to notifications if the offer becomes active.
in the contract, don't save offers that are immediately consummated to the book

It used to always update the counter-offers by asking zoe for fresh
getOfferStatuses(). Now it knows which offer was consumed, so it
directly removes that offer.

A little refactoring to pull out common cases.

This fixes the second problem described in #13 that included a stack trace.
  • Loading branch information
Chris-Hibbert committed Apr 24, 2020
1 parent 958a2c0 commit fd585b1
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 14 deletions.
10 changes: 9 additions & 1 deletion packages/cosmic-swingset/lib/ag-solo/vats/lib-wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,15 @@ export async function makeWallet(
return E(cancelObj).cancel();
});
idToOfferHandle.set(id, offerHandle);
subscribeToNotifier(id, offerHandle);
// The offer might have been added to the book, or it might have been
// immediately consummated. Only subscribe if it was added to the book.
E(zoe)
.isOfferActive(offerHandle)
.then(active => {
if (active) {
subscribeToNotifier(id, offerHandle);
}
});

// The outcome is most often a string that can be returned, but
// it could be an object. We don't do anything currently if it
Expand Down
49 changes: 36 additions & 13 deletions packages/zoe/src/contracts/simpleExchange.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,35 @@ export const makeContract = harden(zcf => {
updater.updateState(getBookOrders());
}

// If there's an existing offer that this offer is a match for, make the trade
// and return the handle for the matched offer. If not, return undefined, so
// the caller can know to add the new offer to the book.
function swapIfCanTrade(offerHandles, offerHandle) {
for (const iHandle of offerHandles) {
if (canTradeWith(offerHandle, iHandle)) {
const swapResult = swap(offerHandle, iHandle);
bookOrdersChanged();
return swapResult;
swap(offerHandle, iHandle);
// return handle to remove
return iHandle;
}
}
bookOrdersChanged();
return defaultAcceptanceMsg;
return undefined;
}

// try to swap offerHandle with one of the counterOffers. If it works, remove
// the matching offer and return the remaining counterOffers. If there's no
// matching offer, add the offerHandle to the coOffers, and return the
// unmodified counterOfffers
function swapIfCanTradeAndUpdateBook(counterOffers, coOffers, offerHandle) {
const handle = swapIfCanTrade(counterOffers, offerHandle);
if (handle) {
// remove the matched offer.
counterOffers = counterOffers.filter(value => value !== handle);
} else {
// Save the order in the book
coOffers.push(offerHandle);
}

return counterOffers;
}

const exchangeOfferHook = offerHandle => {
Expand All @@ -89,20 +108,24 @@ export const makeContract = harden(zcf => {
want: { Price: null },
});
if (checkIfProposal(offerHandle, sellAssetForPrice)) {
// Save the valid offer and try to match
sellOfferHandles.push(offerHandle);
buyOfferHandles = [...zcf.getOfferStatuses(buyOfferHandles).active];
return swapIfCanTrade(buyOfferHandles, offerHandle);
buyOfferHandles = swapIfCanTradeAndUpdateBook(
buyOfferHandles,
sellOfferHandles,
offerHandle,
);
/* eslint-disable no-else-return */
} else if (checkIfProposal(offerHandle, buyAssetForPrice)) {
// Save the valid offer and try to match
buyOfferHandles.push(offerHandle);
sellOfferHandles = [...zcf.getOfferStatuses(sellOfferHandles).active];
return swapIfCanTrade(sellOfferHandles, offerHandle);
sellOfferHandles = swapIfCanTradeAndUpdateBook(
sellOfferHandles,
buyOfferHandles,
offerHandle,
);
} else {
// Eject because the offer must be invalid
return rejectOffer(offerHandle);
}
bookOrdersChanged();
return defaultAcceptanceMsg;
};

const makeExchangeInvite = () =>
Expand Down

0 comments on commit fd585b1

Please sign in to comment.