Skip to content

Commit

Permalink
refactor(zoe)!: handle subtracting empty in a less fragile way (#3345)
Browse files Browse the repository at this point in the history
* chore: handle subtracting empty in a less fragile way
  • Loading branch information
katelynsills authored Jun 18, 2021
1 parent d8952c2 commit f51d327
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 19 deletions.
29 changes: 20 additions & 9 deletions packages/zoe/src/contractFacet/allocationMath.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@ import { AmountMath } from '@agoric/ertp';
*/
const doOperation = (allocation, amountKeywordRecord, operationFn) => {
const allKeywords = Object.keys({ ...allocation, ...amountKeywordRecord });
return Object.fromEntries(
allKeywords.map(keyword => [
keyword,
operationFn(allocation[keyword], amountKeywordRecord[keyword], keyword),
]),
);

const entries = allKeywords
.map(keyword => {
const result = operationFn(
allocation[keyword],
amountKeywordRecord[keyword],
keyword,
);
return [keyword, result];
})
.filter(([_keyword, result]) => result !== undefined);

return Object.fromEntries(entries);
};

/** @type {Operation} */
Expand All @@ -46,7 +53,13 @@ const add = (amount, amountToAdd, _keyword) => {

/** @type {Operation} */
const subtract = (amount, amountToSubtract, keyword) => {
if (amountToSubtract !== undefined) {
// if amountToSubtract is undefined OR is defined, but empty
if (amountToSubtract === undefined || AmountMath.isEmpty(amountToSubtract)) {
// Subtracting undefined is equivalent to subtracting empty, so in
// both cases we can return the original amount. If the original
// amount is undefined, it is filtered out in doOperation.
return /** @type {Amount} */ (amount);
} else {
assert(
amount !== undefined,
X`The amount could not be subtracted from the allocation because the allocation did not have an amount under the keyword ${keyword}.`,
Expand All @@ -57,8 +70,6 @@ const subtract = (amount, amountToSubtract, keyword) => {
);
return AmountMath.subtract(amount, amountToSubtract);
}
// Subtracting undefined is equivalent to subtracting empty.
return /** @type {Amount} */ (amount);
};

/**
Expand Down
5 changes: 0 additions & 5 deletions packages/zoe/src/contracts/newSwap/collectFees.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
// @ts-check

import { AmountMath } from '@agoric/ertp';

export const makeMakeCollectFeesInvitation = (zcf, feeSeat, centralBrand) => {
const collectFees = seat => {
// Ensure that the feeSeat has a stagedAllocation with a RUN keyword
feeSeat.incrementBy({ RUN: AmountMath.makeEmpty(centralBrand) });
const amount = feeSeat.getAmountAllocated('RUN', centralBrand);

seat.incrementBy(feeSeat.decrementBy({ RUN: amount }));
zcf.reallocate(seat, feeSeat);

Expand Down
8 changes: 3 additions & 5 deletions packages/zoe/test/unitTests/zcf/test-reallocate-empty.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@ test(`zcf.reallocate introducing new empty amount`, async t => {

const empty = AmountMath.makeEmpty(brand, AssetKind.NAT);

// decrementBy empty
t.throws(() => zcfSeat1.decrementBy({ RUN: empty }), {
message:
'The amount could not be subtracted from the allocation because the allocation did not have an amount under the keyword "RUN".',
});
// decrementBy empty does not throw, and does not add a keyword
zcfSeat1.decrementBy({ RUN: empty });
t.deepEqual(zcfSeat1.getStagedAllocation(), {});

// Try to incrementBy empty. This succeeds, and the keyword is added
// with an empty amount.
Expand Down

0 comments on commit f51d327

Please sign in to comment.