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

contracts: Add interfaces #80

Closed
wants to merge 1 commit into from
Closed

contracts: Add interfaces #80

wants to merge 1 commit into from

Conversation

bingen
Copy link
Collaborator

@bingen bingen commented Mar 11, 2024

First draft of interfaces changes for the frontend.
I skipped:

  • Anything related to redemptions, as they won’t be implemented in the frontend
  • Combined operations. Let’s do this the other way around: once we know which operations the frontend is adding, I’ll add them to the contracts.

@bingen bingen self-assigned this Mar 11, 2024
@liquity liquity deleted a comment from vercel bot Mar 11, 2024
@danielattilasimon
Copy link
Collaborator

danielattilasimon commented Mar 12, 2024

Regarding combined operations: could we keep those outside the core contracts, i.e. in zapper contracts using "on behalf of" functionality? Just a thought.

Edit: I guess we should bake in at least a combined open Trove + delegate, as it could save some gas (to be seen).


function claimCollateral() external;
function delegateInterest(uint256 _troveId, address _delegate) external;
Copy link
Collaborator

Choose a reason for hiding this comment

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

How do you undelegate? Is the idea to reuse adjustTroveInterestRate() for that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was thinking of delegating to zero address (or to owner), but that’s an option too.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I thought of adjustTroveInterestRate() because I expect many people to also change their interest rate at the time of undelegation, so this would save an operation.

Copy link
Collaborator

@danielattilasimon danielattilasimon Mar 20, 2024

Choose a reason for hiding this comment

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

Upon further thought, there should probably be 2 different calls for interest rate delegation:

  • delegateInterestRateToIndividualManager(troveId, manager, min, max)
  • delegateInterestRateToBatchManager(troveId, batchManager)

The first one would grant the arbitrary address "manager" the right to call adjustTroveInterestRate() on the Trove with an interest rate within range of [min, max]. The owner of the Trove can undelegate by passing a zero address (or their own address) to the same function, like you suggested.

The second form is for batch delegation (duh) and requires batchManager address to have previously registered themselves as a batch manager, providing a [min, max] range (as well as a management fee) which can't be changed later. Undelegation in this case involves removing the Trove from the batch and reinserting it into a new position in the list, most likely even if the owner continues to use the last interest rate set by the batch manager (because batches must be kept contiguous). As such, we could either reuse adjustTroveInterestRate() for undelegation (and have it recognize when a Trove is part of a batch, and perform removal), or have a dedicated function that shares some of its internals with adjustTroveInterestRate(). I tend to prefer the latter as I dislike functions that branch too much, so I would add one more function:

  • undelegateInterestRateFromBatchManager(troveId, newAnnualInterestRate, upperHint, lowerHint)

Copy link
Collaborator

@danielattilasimon danielattilasimon Mar 20, 2024

Choose a reason for hiding this comment

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

Actually, we probably have to add hints to batch delegation too, as in:

  • delegateInterestRateToBatchManager(troveId, batchManager, upperHint, lowerHint)

Most of the time, hints won't be crucial as each batch will store "pointers" to both ends of its slice of the list for the purpose of quickly skipping over the entire batch, which can be used to find the correct insertion point on-chain. However, if a batch is empty, we don't know the correct position of constituents yet, so we need a hint.

Alternatively, we could put placeholder nodes in the list for each batch manager (or just empty batches) where new Troves are to be inserted, but this could be abused (spamming the list full of useless empty batches that make traversing the list costly, e.g. when redeeming). For that reason, I prefer hints.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, your reasoning above make a lot of sense to me. Feel free to add a commit with those new function signatures so they don’t get lost in this comments.
Thanks!

@@ -24,25 +24,29 @@ interface IBorrowerOperations is ILiquityBase {
address _boldTokenAddress
) external;

function openTrove(uint _maxFee, uint256 _ETHAmount, uint _boldAmount, address _upperHint, address _lowerHint, uint256 _annualInterestRate) external;
function openTrove(address _owner, uint256 _ownerIndex, uint _maxFee, uint256 _ETHAmount, uint _boldAmount, address _upperHint, address _lowerHint, uint256 _annualInterestRate, uint256 _spDeposit) external;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know combined operations will be coming later, but there's one that's worth considering already: opening a Trove with a delegated interest rate.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Definitely! Good idea.


function adjustTrove(uint _maxFee, uint _collChange, bool _isCollIncrease, uint _debtChange, bool isDebtIncrease) external;
function adjustTrove(uint256 _troveId, uint _maxFee, uint _collChange, bool _isCollIncrease, uint _debtChange, bool isDebtIncrease) external;
Copy link
Collaborator

@danielattilasimon danielattilasimon Mar 12, 2024

Choose a reason for hiding this comment

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

Is _maxFee still needed? I know there's still an upfront interest payment (1 week's worth), but it's no longer unpredictable, like the borrow fee in v1 (unless you're delegating I guess, which is not the case for normal openTrove() / adjustTrove() / withdrawBold().

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point. I’ll remove it.

/* buyETHBatch():
* Swap ETH to Bold using opt-in swap facility liquidation gains, from multiple depositors
*/
function buyETHBatch(address[] calldata _depositors, uint256 _ethAmount) external;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Haven't thought this through, but shouldn't _ethAmount also be an array (of how much to buy from each depositor)? Or is the idea to move on from one depositor to the next when its intent is fully used up?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, my idea was the latter. I’m assuming you would order the array from most favorable to least.

@danielattilasimon
Copy link
Collaborator

danielattilasimon commented Mar 12, 2024

Noticed there are no changes related to multi-collateral. I guess the idea is to have multiple instances of TroveManager/BorrowerOperations/StabilityPool etc., and redemption would be moved to its own contract as it interacts with every collateral type, right? Will each collateral have its own NFT contract for Troves, or do we want it to be shared?

@bingen
Copy link
Collaborator Author

bingen commented Mar 12, 2024

Noticed there are no changes related to multi-collateral. I guess the idea is to have multiple instances of TroveManager/BorrowerOperations/StabilityPool etc., and redemption would be moved to its own contract as it interacts with every collateral type, right?

Yes, exactly.

Will each collateral have its own NFT contract for Troves, or do we want it to be shared?

Yes, that was my idea, to keep it simpler (in terms of backend code). If these NFTs were to be traded on OpenSea and the like, it would be confusing, but I don’t think that’s the case. We just care about transferFrom, and frontends can handle the different contracts. Does that sound good to you?


function addColl(uint256 _ETHAmount) external;
function addColl(uint256 _troveId, uint256 _ETHAmount) external;
Copy link
Contributor

Choose a reason for hiding this comment

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

Does _ETHAMount (and generally, the term ETH) represent WETH and LSTs in the contracts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, exactly. Technically it’s actually any ERC20 used as collateral, but in our case it will be WETH and some LSTs.

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

Successfully merging this pull request may close these issues.

3 participants