Skip to content

refactor(run-protocol): move config of charging and recording periods to vault factory #4394

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

Merged
merged 16 commits into from
Feb 1, 2022

Conversation

turadg
Copy link
Member

@turadg turadg commented Jan 26, 2022

closes: #4185

Description

Moves the loan calculation periods (charging and recording) from governance params on each vault manager (collateral type) to the vault factory as a whole.

Security Considerations

See #4185

Documentation Considerations

Needs documenting

Testing Considerations

Period governance probably needs testing. Will be addressed in #4432

* @param {string} [message]
* @returns {T}
*/
export function assertDefined(val, message) {
Copy link
Member Author

Choose a reason for hiding this comment

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

@erights WDYT of this? similar to Nat but for a nullish check. See below for an example in action.

@turadg turadg force-pushed the ta/vault-periods-immutable branch from 18cd189 to a914f32 Compare January 26, 2022 20:42
@mhofman
Copy link
Member

mhofman commented Jan 26, 2022

IMO the problem here is that getLoanParams is not sufficiently typed, and is a simple indexed access, which means the type may come back as undefined.

I don't disagree that an assertNonNullish would be valuable, but it should be reserved for places where not just used for satisfying the type checker.

Comment on lines 60 to 71
/**
* @template T
* @param {T | null | undefined} val
* @param {string} [message]
* @returns {T}
*/
export function assertDefined(val, message) {
if (val != null) {
return val;
}
throw Error(message !== undefined ? message : `unexpected ${val}`);
}
Copy link
Member

Choose a reason for hiding this comment

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

I like the idea of it, but have some questions. The assert module is migrating from agoric-sdk to endo anyway. But wherever it is, it should be written in our normal assertFoo style. The following is how I might write it.

Also, please don't write function functions. We have essentially adopted an arrow-only style. We have not yet taken the time to convert old code. But new code should be in arrow-only style unless there's a good stated reason otherwise.

Also, you're exporting a non-hardened value.

Suggested change
/**
* @template T
* @param {T | null | undefined} val
* @param {string} [message]
* @returns {T}
*/
export function assertDefined(val, message) {
if (val != null) {
return val;
}
throw Error(message !== undefined ? message : `unexpected ${val}`);
}
/**
* @template T
* @param {T | null | undefined} val
* @param {string} [optDetails]
* @returns {T}
*/
export const assertDefined = (val, optDetails = X`unexpected ${q(val)}`) => {
if (val != null) {
// This `!= null` idiom checks that `val` is not `null` nor `undefined`.
return val;
}
assert.fail(optDetails);
};
harden(assertDefined);

Also, I'm not sure I like "defined" as the opposite of "nullish". But I cannot think of a better one.

Copy link
Member Author

Choose a reason for hiding this comment

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

Apropos naming, is there a better term than "assert"? In SES, global assert mostly return void but this one returns the argument.

I could see someone being surprised by one or the other. For consistency, would it be better to return the argument when asserting a type or to have a different verb for this version that returns its argument? cc @kriskowal

Copy link
Member

Choose a reason for hiding this comment

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

This is a good point. I agree that we should not have a function named assertFoo that returns its argument. This is indeed inconsistent with both precedents: The assertFoo functions we have don't return their argument, and the validating or coercing functions we have that do return their argument, or a coerced-to-validated form of their argument, like Nat, and written simply naming the property they assure about their return result. This one at least is written with an initial upper case, mirroring similar usage of String, BigInt etc.

How about simply NotNullish ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

I have in hobby projects found it useful to distinguish assert* (returns void) from assume* (returns argument), though one could argue that all assume functions could just be assert and ignore the return.

https://github.com/borkshop/js/blob/main/cube/assert.js

Not having to name an intermediate variable in an expression like this is useful:

const location = assumeDefined(locations.get(entityId), X`No entity for identifier ${q(entityId)}`);

Copy link
Member Author

Choose a reason for hiding this comment

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

With some refactoring I don't need this anymore but I still think it would be useful. Pulling out to #4422 and removing you from reviewers for this PR.

dckc
dckc previously requested changes Jan 27, 2022
Comment on lines 15 to 19
import {
CHARGING_PERIOD,
RECORDING_PERIOD,
} from '@agoric/zoe/src/contracts/loan';

Copy link
Member

Choose a reason for hiding this comment

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

That's an example contract that, according to #1656, should move out of Zoe. Let's not use that as the source of truth for this.

@turadg turadg force-pushed the ta/vault-periods-immutable branch from a914f32 to 5537785 Compare January 31, 2022 16:15
@turadg turadg requested a review from dckc January 31, 2022 18:24
@turadg turadg marked this pull request as ready for review January 31, 2022 18:58
@turadg turadg dismissed erights’s stale review January 31, 2022 19:00

the NonNullish utility for which changes were requested has been pulled out (#4422)

Copy link
Member

@dckc dckc left a comment

Choose a reason for hiding this comment

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

I don't see a test for the fix / feature / design change. I suggest a test that changes the recording period and checks that it affects vaults of multiple collateral brands.

@@ -49,6 +51,8 @@ const handleParamGovernance = (zcf, paramManager) => {
...originalPublicFacet,
getSubscription: () => paramManager.getSubscription(),
getContractGovernor: () => electionManager,
/** @type {GetGovernedVaultParams} */
// @ts-expect-error we know this ParamManagerFull is really a GetGovernedVaultParams
Copy link
Member

Choose a reason for hiding this comment

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

Not for this PR, but...

I suspect there's a way to avoid type conflicts like this by parameterizing types such as ParamManagerFull.

It looks like I didn't file an issue, but I did some related work in https://github.com/Agoric/agoric-sdk/commits/claims-registar-dc-review esp 88b28e9 .

Comment on lines 5 to 7
/**
* @param {bigint} value
*/
Copy link
Member

Choose a reason for hiding this comment

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

In the interest of vertical code density, for single-parameter functions, I usually do:

Suggested change
/**
* @param {bigint} value
*/
/** @param {bigint} value */

This reduces consistency somewhat. And if the function later takes more than one parameter, there is some churn. So it's a matter of taste.

// @ts-ignore It's a VaultParamManager
/**
* @param {LoanTiming} initialValues
* @returns {ParamManagerFull & {
Copy link
Member

Choose a reason for hiding this comment

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

nice.

};

/**
* XXX maybe call this "loan terms"?
Copy link
Member

Choose a reason for hiding this comment

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

to whom is this XXX comment directed? Why call it "loan terms"? Is there something wrong with the current name? if so, what?

Copy link
Member Author

Choose a reason for hiding this comment

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

The XXX is directed at whoever is reading this code, but I think this one can be resolved before merging.

I thought "terms" instead of "rates" because while it includes interestRate it also has initialMargin, liquidationMargin and loanFee. The latter don't seem like rates to me but they are part of the terms of the loan.

I didn't make the change because I thought maybe the charging and recording period could be considered terms of the loan… but since those are parameters of the whole vault factory they aren't part of any particular loan.

So I think Terms is better than Rates. But I'm not as sure about the "Loan" term (pun intended) because vaults, while they share some mechanics with loans, are explicitly not loans. Maybe ChargingTerms?

Copy link
Member

Choose a reason for hiding this comment

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

I have some hesitation about changing this name, as it's not required to address #4185 . It's a bit of a "drive-by." Plus, I feel a little like when my spouse asks me whether I like the new paint color; I just don't have an opinion.

OTOH, @dtribble did ask you to look into naming issues such as this. See if you can grab him briefly?

For somewhat arbitrary issues like this, I'm kinda inclined to fall back on an executive hierarchy (#3382); that is: talk about it with @Chris-Hibbert .

I guess if it's between you and me: I'll agree to a change if you think it's sufficiently worthwhile to add a test :)
Is it part of the package's external API? If so, that makes it a breaking change, yes? So it would need its own conventional commit to get it in the CHANGELOG. (or do we use NEWS.md in this package?)

Copy link
Member Author

@turadg turadg Jan 31, 2022

Choose a reason for hiding this comment

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

Good call that it's out of scope. I've cut it and will look into it separately.

Good question about breaking change… changing the TS type wouldn't break API but this refactoring does change how debts are calculated. However I don't think it breaks any external assumptions because Agoric controls the governance of both the vault factory and vault managers (the destination and source for timing governance)

*/

/**
* @typedef {Object} ParamManagerBase
* @property {GetParams} getParams
* @property {() => Record<Keyword,ParamShortDescription>} getParams
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* @property {() => Record<Keyword,ParamShortDescription>} getParams
* @property {() => Record<Keyword, ParamShortDescription>} getParams

Copy link
Member Author

@turadg turadg Jan 31, 2022

Choose a reason for hiding this comment

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

Thanks. Among the downside of type defs being in jsdoc comments. In .ts file Prettier would autoformat.

We have 95 Record with space and 18 without it.

Comment on lines +21 to +23
/**
* @param {Amount} electorateInvitationAmount
*/
Copy link
Member

Choose a reason for hiding this comment

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

again, please consider a more dense/concise form:

Suggested change
/**
* @param {Amount} electorateInvitationAmount
*/
/** @param {Amount} electorateInvitationAmount */

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm convinced.

As you said above, there's a trade-off with comment churn when another param is added. But on balance I think it's better to have the concise form. Comments have less need for git blame.

@@ -16,7 +16,7 @@
*/

/**
* @typedef {Object} Rates
* @typedef {Object} Rates - XXX loan terms?
Copy link
Member

Choose a reason for hiding this comment

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

another XXX. I'm not sure what to do with these.

If they are intended to land on master, ideally they would have corresponding issue #s.

*/

/**
* @callback MakeVaultParamManager
Copy link
Member

Choose a reason for hiding this comment

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

Good riddance to the use of @callback for something that isn't actually passed around as a callback.

Comment on lines +46 to +47
* 'ChargingPeriod': ParamRecord<'relativeTime'> & { value: RelativeTime },
* 'RecordingPeriod': ParamRecord<'relativeTime'> & { value: RelativeTime },
Copy link
Member

Choose a reason for hiding this comment

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

again: why quote these keys?

Suggested change
* 'ChargingPeriod': ParamRecord<'relativeTime'> & { value: RelativeTime },
* 'RecordingPeriod': ParamRecord<'relativeTime'> & { value: RelativeTime },
* ChargingPeriod: ParamRecord<'relativeTime'> & { value: RelativeTime },
* RecordingPeriod: ParamRecord<'relativeTime'> & { value: RelativeTime },

Copy link
Member Author

Choose a reason for hiding this comment

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

vestiges of refactoring I guess. will remove.

Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't seem to have been cleaned up before merge?

Copy link
Member Author

Choose a reason for hiding this comment

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

mea culpa. I'll include in another PR

@dckc dckc dismissed their stale review January 31, 2022 20:49

addressed

@turadg turadg changed the title move config of charging and recording periods to chain startup refactor: move config of charging and recording periods to vault factory Feb 1, 2022
@turadg turadg force-pushed the ta/vault-periods-immutable branch from fc86778 to 1c04948 Compare February 1, 2022 20:13
@turadg
Copy link
Member Author

turadg commented Feb 1, 2022

I don't see a test for the fix / feature / design change. I suggest a test that changes the recording period and checks that it affects vaults of multiple collateral brands.

Good suggestion, @dckc . Given the state of swingset testing in run-protocol, I discussed with Dean in standup and we agreed to punt to a more comprehensive look at test coverage #4432

PTAAL

@turadg turadg requested a review from dckc February 1, 2022 20:16
Copy link
Member

@dckc dckc left a comment

Choose a reason for hiding this comment

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

postponing testing is very much not my style, but let's give it a try (#4432).

@turadg turadg changed the title refactor: move config of charging and recording periods to vault factory refactor(run-protocol): move config of charging and recording periods to vault factory Feb 1, 2022
@turadg turadg added the automerge:squash Automatically squash merge label Feb 1, 2022
@mergify mergify bot merged commit d7b69bd into master Feb 1, 2022
@mergify mergify bot deleted the ta/vault-periods-immutable branch February 1, 2022 22:40
* @callback GetParams - getParams() retrieves a Record containing
* keyword pairs with descriptions of parameters under governance.
* @returns {Record<Keyword,ParamShortDescription>}
* @callback GetGovernedVaultParams
Copy link
Contributor

Choose a reason for hiding this comment

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

@turadg governance shouldn't know about vaults.

This looks like it's actually about Vaults, so I'd like to move it. Is there a reason it needs to be here?

Copy link
Member Author

Choose a reason for hiding this comment

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

This was a best effort to get the types consistent. Feel free to improve!

Copy link
Member

Choose a reason for hiding this comment

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

I sorta moved it back in #4437

@@ -539,7 +544,7 @@
* @typedef {Object} GovernedPublicFacet
* @property {() => Subscription<ParamDescription>} getSubscription
* @property {VoteOnParamChange} getContractGovernor
* @property {GetParams} getGovernedParams - get descriptions of
* @property {GetGovernedVaultParams} getGovernedParams - get descriptions of
Copy link
Contributor

Choose a reason for hiding this comment

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

@turadg

It may be the case that the only actual use of this is in Vaults, but the support in Governance should be more generic. Is there a way to have a generic GetParams here, and override it with something more specific in Vaults?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, if in the vaults we use something more specific instead of GovernedPublicFacet. Happy to work together on the specifics.

Comment on lines +46 to +47
* 'ChargingPeriod': ParamRecord<'relativeTime'> & { value: RelativeTime },
* 'RecordingPeriod': ParamRecord<'relativeTime'> & { value: RelativeTime },
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't seem to have been cleaned up before merge?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:squash Automatically squash merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Vault periods should be static
6 participants