-
Notifications
You must be signed in to change notification settings - Fork 212
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
feat: fusdc advancer #10420
feat: fusdc advancer #10420
Conversation
Deploying agoric-sdk with Cloudflare Pages
|
751d762
to
ffe20a3
Compare
444aedd
to
88f51f3
Compare
725edd7
to
3483477
Compare
88f51f3
to
c1b9538
Compare
3483477
to
9c4e291
Compare
8acd20c
to
a92b0ec
Compare
229333d
to
6f0bd04
Compare
9eac623
to
f3d1e36
Compare
37d455f
to
1673c45
Compare
import { assertAllDefined } from '@agoric/internal'; | ||
import { ChainAddressShape } from '@agoric/orchestration'; | ||
import { pickFacet } from '@agoric/vat-data'; |
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.
out of scope, but this helper should move eventually. It's about Exos, not vat data.
We could move it down to @agoric/internal
but that is meant to not be consumed externally and this is valuable to other contract authors.
I wonder if it belongs in Endo.
*/ | ||
|
||
/** type guards internal to the AdvancerKit */ | ||
const WatcherHandlersShape = { |
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.
Shape
is for objects that get passed around. This is an interface guard. It's a kit interface guard but you could still call it AdvancerI
.
Why is this defined here and then composed with advancer
in the Exo interface param?
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.
I was getting cute and trying to obscure the Vow handlers from the actual external interface. Changed to AdvancerI
* @param {LogFn} caps.log | ||
* @param {StatusManager} caps.statusManager | ||
* @param {VowTools} caps.vowTools | ||
* @param {AdvancerKitCaps} caps |
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 name makes sense. Elsewhere we've called it io
. I don't think the style guide takes a position
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.
powers
is used similarly. Sometimes tools
, though those are usually more closely related.
caps
is not a dictionary word (or rather: it is, but it means "things you put on your head"). For very local usage, that doesn't matter much, but AdvancerKitCaps
looks like something that might have a wider scope. Maybe AdvancerKitPowers
instead?
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.
oh yeah, Powers. I think powers
is strictly better than caps
} | ||
advancer: { | ||
/** | ||
* Returns a Promise for a Vow in the happy path, or undefined |
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.
please put this in @returns
try { | ||
// should LiquidityPool return a vow here? | ||
const { USDC: advancePmtP } = | ||
await assetManagerFacet.borrowUnderlying(requestedAmount); |
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.
what's underlying? did you mean underwriting?
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.
Underlying assets of the pool, not to be confused with shares, the other asset it owns. We can probably simplify to borrow()
and return()
repay()
destination, | ||
amount: requestedAmount.value, | ||
}); | ||
// do we actually need to await here? |
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.
deposit
takes a payment so yes, unless borrowUnderlying
returns a payment instead of a paymentP
const depositV = E(poolAccount).deposit(advancePmt); | ||
return watch(depositV, this.facets.depositHandler, destination); | ||
} catch (e) { | ||
// TODO how should we think about failure here? |
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.
the deposit is unlikely to fail but the borrow could if the balance changes since it was looked up. Even though we're using a ZCFSeat we should design for if this were an ICA.
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.
Ok I've put a TODO for borrow
failing. I think we can flesh that out more when we integrate the with the LiquidityPool
.
For .deposit()
failing, we can catch this separately in onRejected()
and attempt to return the payment. The LP might need an interface for this, or return()
will need to be trained to handle this scenario (right now, it's expected fees + principal).
1673c45
to
9de3393
Compare
9de3393
to
165b3d7
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.
Some small requests. I wouldn't object to them coming in a later PR.
I didn't carefully review error handling because we have that scheduled and it's probably best to tackle that holistically.
*/ | ||
|
||
/** | ||
* Expected interface from LiquidityPool |
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.
I'll assume this @dckc agrees
* chainHub: ChainHub; | ||
* log: LogFn; | ||
* statusManager: StatusManager; | ||
* USDC: { brand: Brand<'nat'>; denom: Denom; }; |
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.
non-blocking: I think we should refer to this as usdc
in code. Treat "USDC" as a word and capitalize accordingly. Fully capitalized initialisms are to convey that each letter represents another word (United States Dollar Coin) but that's not relevant to the contract.
* localDenom: Denom; | ||
* poolAccount: HostInterface<OrchestrationAccount<{ chainId: 'agoric' }>>; | ||
* assetManagerFacet: AssetManagerFacet; | ||
* poolAccount: ERef<HostInterface<OrchestrationAccount<{chainId: 'agoric';}>>> |
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.
nit: ;
unnecessary and a little distracting
localDenom: M.string(), | ||
poolAccount: M.remotable(), | ||
assetManagerFacet: M.remotable(), | ||
poolAccount: M.or(VowShape, M.remotable()), |
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.
TODO pick one
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 seems like it'll depend on:
- how we create the LCA (I believe
zone.makeOnce()
will return a Vow) - what incarnation we're in (first time it's a
Vow
, subsequently, aRemotable
)
packages/fast-usdc/src/typeGuards.js
Outdated
@@ -37,3 +37,8 @@ export const PendingTxShape = { | |||
status: M.or(...Object.values(PendingTxStatus)), | |||
}; | |||
harden(PendingTxShape); | |||
|
|||
export const QueryParamsShape = { |
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 is too generic and is easily confused with QueryParamsShape
in address.js
consider EudParamShape
|
||
/** | ||
* Default pattern matcher for `getQueryParams`. | ||
* Does not assert keys exist, but ensures existing keys are strings. |
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.
I think this is already guaranteed by your parser, but it doesn't hurt
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.
Agree for the getQueryParams
fn, but {}
seems to satisfy M.splitRecord({}, {}, M.recordOf(M.string(), M.string()))
165b3d7
to
99707ef
Compare
refs: #10390
Description
LiquidityPool
PoolAccount
Security Considerations
Deals with live payments and ensures they do not get lost during failure paths
Scaling Considerations
No new ones introduced
Documentation Considerations
Testing Considerations
Includes tests
Upgrade Considerations
NA, unreleased