-
Notifications
You must be signed in to change notification settings - Fork 217
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
OfferTo as a Zoe Helper - ready for design review #2016
Conversation
dc23155
to
0fbe9d2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that when then offerTo implementation is moved into Zoe, we will be able to get rid of a few parameters since it will probably be a method on the fromSeat
fromSeat.offerTo(invitation, proposal, fromAssets, toSeat, keywordMapping);
I'm surprised that it would make sense to give the responsibility to one zcfSeat to reallocate the results to another seat. I agree that that reduces the number of extraneous parameters, but it seems like an odd place for the behavior to go.
Just off the top of my head, but something like one of these
toSeat.transferFrom(fromSeat.transferVia(invitation, proposal, fromAssets), keywordMapping);
or
fromSeat.transferVia(invitation, proposal, fromAssets).transferTo(toSeat, keywordMapping);
Hmm, it makes sense to me. The Your two proposals would fail as written because both the making of the offer and the depositing of the payouts need the |
8cc1d6e
to
e366380
Compare
50cef77
to
6e2033d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really good. I have some very local comments on docs and formatting.
* | ||
* @param {AmountKeywordRecord | PaymentPKeywordRecord | undefined } | ||
* keywordRecord | ||
* @param {KeywordKeywordRecord} keywordMapping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this have an @returns
clause?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good catch, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I just tried this and if I say that the return value is {AmountKeywordRecord | PaymentPKeywordRecord | undefined }, it is not smart enough to know that the same kind will be returned. I don't know how to specify this. But with this return value, I get errors in offerTo
saying that I can't pass something potentially undefined to the other methods that use the result of mapKeywords
await deposited; | ||
offerResultP.then(closeSuccessfully, closeWithFailure); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to use Promise.all([deposited, offerResult]).then(
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have to ensure the deposit on the lenderSeat is done before the lenderSeat is exited.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point was that in both cases, we wait for both promises to complete. The present code waits for them in order, but doesn't force the deposit
to happen before the offer. The offerResult promise was created earlier, and its execution is unblocked.
The reason I suggested the change is because the consistent treatment of the two promises that we're waiting for with a single Promise.all()
seems cleaner syntactically.
The only difference in execution that I can see is that if deposited
fails, the present code wouldn't call closeWithFailure
, while the combined version would. I presume this would actually be an improvement, and the reason it wasn't done initially was that a failure in the deposit was seen as unlikely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, let me think about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok, I think I figured out what is going on here. You're right that in the case that both promises resolve, we wait for deposited
to resolve before the lenderSeat
exits, so that case works. However, when the offerHandler
throws, we try to exit the lenderSeat
before it is deposited to. This is because Promise.all() rejects immediately if any of the promises reject individually, so what happens if we have Promise.all([deposited, offerResult]).then(
is that we do not await deposited
before trying to exit the lenderSeat in closeWithFailure
. But, we do want to always deposit
first, so that's not the right behavior.
We want to await deposited
regardless of whether offerResultP
rejects or not, so I think the original version is the better option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good questions. If deposited
rejects, then we have profoundly misunderstood something and it's unclear how we should recover. This would mean that we could not deposit the payouts (refund or otherwise) to the lenderSeat. We do have access to the payouts through the autoswapUserSeat
but it's not clear how we would deposit again in a way that would be successful given that our earlier attempt failed. The reason why offerResultP
rejecting is handled better is that it assumes that deposited
likely resolves due to a refund payout, and we can safely exit lenderSeat
because it got the refund.
Likewise, if deposited
never settles, something has gone horribly wrong, because 1) autoswap
always exits the seat quickly and 2) even in the case of error in autoswap, we should still get a payout that we can deposit safely. Without having deposited a refund successfully it is unclear how we should recover. For instance, we don't want to exit seats or shutdown the contract if only the contract has access to payments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me know if any of these conversations should hold up the PR. Chris has already approved and I think it's ready to merge once the CI passes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If our definition of issuer misbehavior includes rejection or never settling under these conditions, then the behavior you describe is consistent with our threat model for payout liveness. For any given seat, a misbehaving issuer among the issuers that this seat explicitly mentions in its offer, that issuer can block payout liveness for the seat as a whole. This is just another instance of that same allowed failure mode. The security claim we need to make for payout liveness in the face of issuer misbehavior is only
A misbehaving issuer cannot block payout liveness for seats that do not mention that issuer as an issuer in their offer.
Btw, we need to gather such precise statements of the security claims we are making, both for what they include and what they exclude.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me know if any of these conversations should hold up the PR. Chris has already approved and I think it's ready to merge once the CI passes
I still see no reason for this to block on me. Please proceed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw, we need to gather such precise statements of the security claims we are making, both for what they include and what they exclude.
For this claim, already done though it should be refined.
https://github.com/Agoric/agoric-sdk/wiki/Limited-Risk-from-Bad-Issuers
9652d21
to
1c38ba3
Compare
In this PR,
offerTo
is written as a helper. It is incorporated into the loan's liquidation code and the OTC desk code with those contracts' tests passing. This code is in a good state for a cursory design review of theofferTo
signature:Types:
Where
invitation
is the invitation to contractB,proposal
is the proposal to use with the invitation, andkeywordMapping
is a record of the keywords appropriate to contractA mapped to the keywords for contractB.Note that when then
offerTo
implementation is moved into Zoe in another PR, we will be able to get rid of thezcf
parameter: