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

refactor!: new reallocate API to assist with reviewing conservation of rights #3184

Merged
merged 4 commits into from Jun 8, 2021

Conversation

katelynsills
Copy link
Contributor

@katelynsills katelynsills commented May 26, 2021

This PR makes a breaking change to ZCFSeats, zoe.reallocate, and the trade, swap, and swapExact helpers.

SeatStagings and zcfSeat.stage no longer exist. Instead, amountKeywordRecords can be added or subtracted to a seat's allocation by calling methods directly on the zcfSeat:

{(amountKeywordRecord: AmountKeywordRecord) => AmountKeywordRecord} incrementBy - the amountKeywordRecord to be added to the seat's staged allocation
{(amountKeywordRecord: AmountKeywordRecord) => AmountKeywordRecord} decrementBy - the amountKeywordRecord to be subtracted from the seat's staged allocation
{() => void} clear - delete the staged allocation, if any
{() => Allocation} getStagedAllocation - get the stagedAllocation, the allocation that will be committed if the seat is reallocated over, if offer safety holds and rights are conserved
{() => boolean} hasStagedAllocation - whether there is a staged allocation, i.e. whether incrementBy or decrementBy has been called and clear has not.

Once a seat has a staged allocation, it can be reallocated over by calling zcf.reallocate(zcfSeat1, zcfSeat2, ....). This commits the staged allocation, such it is now the current allocation for that seat.

The trade helper no longer exists, and the swap and swapExact helpers no longer accept errorMsg arguments.

Example usage:

      seat.decrementBy({ In: reducedAmountIn });
      poolSeat.incrementBy({ Central: reducedAmountIn });

      poolSeat.decrementBy({ Secondary: amountOut });
      seat.incrementBy({ Out: amountOut });

      zcf.reallocate(poolSeat, seat);
      seat.exit();

Closes #3215

#dapp-otc-branch: 3184-reallocate-api

Copy link
Member

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review so far. Not finished yet.

I am very encouraged by the overall line shrinkage of this PR!

packages/pegasus/src/pegasus.js Outdated Show resolved Hide resolved
packages/treasury/src/collectRewardFees.js Outdated Show resolved Hide resolved
packages/zoe/src/contractFacet/allocationMath.js Outdated Show resolved Hide resolved
packages/zoe/src/contractFacet/types.js Show resolved Hide resolved
packages/zoe/src/contractFacet/types.js Outdated Show resolved Hide resolved
Comment on lines 238 to 242
if (proposal.want.Collateral) {
vaultSeat.decrementBy(
seat.incrementBy({ Collateral: proposal.want.Collateral }),
);
} else if (proposal.give.Collateral) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that a proposal has both a want.Collateral and a give.Collateral?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is possible that a proposal has both, and from I can tell, the code prior to this PR does not prevent it or account for it.

packages/treasury/src/vault.js Show resolved Hide resolved
packages/zoe/src/contractFacet/contractFacet.js Outdated Show resolved Hide resolved
packages/zoe/src/contracts/autoswap.js Outdated Show resolved Hide resolved
packages/zoe/src/contracts/coveredCall.js Show resolved Hide resolved
@erights erights self-requested a review June 2, 2021 03:26
@katelynsills katelynsills force-pushed the 3064-new-reallocate-api branch 2 times, most recently from 6bd2a98 to cc83838 Compare June 5, 2021 00:04
@katelynsills
Copy link
Contributor Author

@erights, this is now ready for review!

@katelynsills
Copy link
Contributor Author

@Chris-Hibbert, could you review the changes to newSwap and packages/treasury? I changed newSwap such that the transfer of rights is easy to audit for conservation.

Copy link
Contributor

@Chris-Hibbert Chris-Hibbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I think it would be better for transferReward() to return feeSeat, so there is a single reallocate() call.

The refactoring in swap.js looks clean to me. Thanks!

  • I would drop the new TODOs in swap.js, but I won't insist on it if my reasoning isn't persuasive.

packages/treasury/src/stablecoinMachine.js Outdated Show resolved Hide resolved
packages/treasury/src/vault.js Outdated Show resolved Hide resolved
packages/treasury/src/vault.js Outdated Show resolved Hide resolved
packages/zoe/src/contracts/newSwap/swap.js Outdated Show resolved Hide resolved
packages/zoe/src/contracts/newSwap/swap.js Outdated Show resolved Hide resolved
Copy link
Member

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

All suggested changes are about error messages, comments, and one renaming.

packages/zoe/src/contractSupport/types.js Show resolved Hide resolved
* @returns {void}
*/
const commitStagedAllocation = zcfSeat => {
assertActive(zcfSeat);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assert happens after the commit point. If it fails it throws. If it throws, it might throw after some allocations have been committed. This is an excellent example of an assert that should immediately shut down at lease the contract. We already have a zcf.assert for this purpose. However, this is not the assert severity you want for normal uses of assertActive, so you'd end up with an annoying duplication of code.

Any check failure that might fail must happen before the commit point. If the failure here is already obviously impossible, or once it is, then a comment here is fine. Impossible cases can become possible under maintenance mistakes. If the impossible happens and zcfSeat is not active then you're guaranteed a low level failure on line 61 below. When I put in atomic actions, I will need to ensure that any such "cannot happen" throws cause vat termination anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I moved this check earlier and removed it from this function, as I don't think it was being adequately checked before.

packages/zoe/src/contractFacet/zcfSeat.js Show resolved Hide resolved
const commitStagedAllocation = zcfSeat => {
assertActive(zcfSeat);
activeZCFSeats.set(zcfSeat, zcfSeat.getStagedAllocation());
zcfSeatToStagedAllocations.delete(zcfSeat);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The delete on line 62 seems exactly the same as the set on line 61. It should be impossible to get here if zcfSeat is not in zcfSeatToStagedAllocations. If that is not already obviously impossible, it must be made obviously impossible. If it happens anyway we reliable get a low level failure from the delete, which throws within the atomic action. Once I use the atomic action API to ensure that such failures cause immediate vat failure, we're safe even against these specific cannot-happen conditions.

When I will ask you to review the PR that protects such atomic actions, please keep these "impossible" cases in mind.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good. I'll add a comment about this.

import { E } from '@agoric/eventual-send';
import { AmountMath } from '@agoric/ertp';
import { Far } from '@agoric/marshal';

import { isOfferSafe } from './offerSafety';
import { assertRightsConserved } from './rightsConservation';
import { addToAllocation, subtractFromAllocation } from './allocationMath';

/** @type {CreateSeatManager} */
export const createSeatManager = (zoeInstanceAdmin, getAssetKindByBrand) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no type SeatManager or SeatKit. But from the comment on CreateSeatManager I would guess that the record returned at the bottom is the SeatManager. If so, then per our previous discussion, I do not understand why this is createSeatManager rather than makeSeatManager.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unchanged in this PR, so I won't address it here, but I think this is fine, since seatManager is an abstract concept only used internally. Since there is no seatManager reified as an object, I think create is fine as well.

Copy link
Contributor

@Chris-Hibbert Chris-Hibbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One missed duplicated edit, one question. Looking good.

Comment on lines +45 to +47
// TODO: this should be transferred directly from the user such
// that there's no way to accidentally take more than expected
// from the pool.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't mark this copy of the TODO. I think it should also be dropped.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I left it in purposefully. In this case, it is central to secondary, so we can take the protocolFee directly from the user's give

@katelynsills katelynsills enabled auto-merge (squash) June 8, 2021 20:56
@katelynsills katelynsills merged commit f34e5ea into master Jun 8, 2021
@katelynsills katelynsills deleted the 3064-new-reallocate-api branch June 8, 2021 21:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Zoe package: Zoe
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Zoe: contract code performing reallocation should be easy to review
3 participants