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

Sturdy Gen Lender Strategy Review #1

Open
4 tasks done
newmickymousse opened this issue Aug 14, 2022 · 32 comments
Open
4 tasks done

Sturdy Gen Lender Strategy Review #1

newmickymousse opened this issue Aug 14, 2022 · 32 comments

Comments

@newmickymousse
Copy link

newmickymousse commented Aug 14, 2022

Claiming a strategy
Protocol name: Sturdy

Brief Strategy Description: Deposits stablecoins (USDC, USDT, or DAI) to Sturdy's lending pool

Due Diligence Review
Protocol Due Diligence and Path to Prod: here

Once a strategy's due diligence has been approved by the team, the strategist can begin codifying it for code review
Strategy Review
Description: Deposits stablecoins (USDC, USDT, or DAI) to Sturdy's lending pool. Sturdy is a two-sided money market, whose primary differentiator is that collateral is staked, with the yields from staking being used to improve rates for lenders. Yields are paid out automatically in-kind, requiring no additional logic to harvest. There are no fees to deposit or withdraw from Sturdy.

Commit (hash): c1b7021

Tag:

Scope:
contracts/GenericSturdy.sol

Additional References or Repo (Link to underlying protocols or relevant documents): docs.sturdy.finance

Deployed Contract (etherscan link):

Review Ongoing By:

Review Completed By:

@newmickymousse
Copy link
Author

  1. function _lendingPool() internal view returns (ILendingPool lendingPool) {
    lendingPool = ILendingPool(protocolDataProvider.ADDRESSES_PROVIDER().getLendingPool());
    }

    can you store this address/IlendingPool into a variable to avoid calling it to frequently? I have checked the contracts and seems to be a constant (correct me if I'm wrong). You can assign the variable in the initialize function.
  2. address public constant WETH = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);

    WETH not being used in the contract
  3. What are you using isIncentivised for? Do you have incentivized lending pools? If so, how do you harvest them? Is it different from a non-incentivized pool harvest?

@sforman2000
Copy link

Thanks @newmickymousse, these have been fixed in 8aaf6f9

  1. What are you using isIncentivised for? Do you have incentivized lending pools? If so, how do you harvest them? Is it different from a non-incentivized pool harvest?

We don't have incentivized lending pools yet but plan to at some point in the future. We've removed this for now since we don't know how they'll be implemented and we don't plan on launching them in the near-term.

@Schlagonia
Copy link

I would remove the Atoken variable from the constructor and cloning functions. Will make cloning much easier and you can just set it using the lendingPool in the _initiliaze. May want to add a check the returned aToken != address(0)

@Schlagonia
Copy link

Should update this and this modifier to use .strategist() instead of management(). Will need to add that function to the IBaseStrategy interface as well

@Schlagonia
Copy link

Schlagonia commented Aug 15, 2022

Would probably be good to check want balance here as well https://github.com/sturdyfi/yearnV2-generic-lender-strat/blob/master/contracts/GenericLender/GenericSturdy.sol#L128

You can also check against "dust" instead of 0. You probably know better than us how you protocol handles super small amounts and if its possible leave behind or withdraw tiny amounts.

@Schlagonia
Copy link

Schlagonia commented Aug 15, 2022

These two lines make a call that is just made in the aprAfterDeposit() before this function. While aprAfterDeposit() is a view function it is used in every harvest so limiting gas costs is helpful. Can you send the the neccesary variables as function params to avoid redundant calls for large dataTypes and memory usage

@Schlagonia
Copy link

Schlagonia commented Aug 15, 2022

It appears that the current value for reserveData.currentLiquidityRate of all the stable coins is currently 0? Am I reading this correct? I would assume its cause no one is paying interest to borrow?

If so is this expected evert to change? If that is always the expected behavior is there any point in even calcluating this

@Schlagonia
Copy link

Can just declare the variable in this line in the function as the return variable and delete this line and L235

@Schlagonia
Copy link

Do you know how confident you are in this calculation being accurate?

Are you able to use just a linear difference cause you really are just dividing up staked rewards evenly over all deposits rather than an interest rate model?

@sforman2000
Copy link

Thanks @Schlagonia, we'll get to work on these.

It appears that the current value for reserveData.currentLiquidityRate of all the stable coins is currently 0? Am I reading this correct? I would assume its cause no one is paying interest to borrow?

If so is this expected evert to change? If that is always the expected behavior is there any point in even calcluating this

Borrowers start paying interest if the utilization on the borrowed asset goes above 90%, so we still need to calculate it.

Do you know how confident you are in this calculation being accurate?

Are you able to use just a linear difference cause you really are just dividing up staked rewards evenly over all deposits rather than an interest rate model?

Yep, that's exactly what we're doing, and it's been very accurate empirically. The only exception is when utilization goes above 90% as mentioned above, in which case lenders earn interest on top of the collateral staking yield.

@sforman2000
Copy link

@Schlagonia We've pushed fixes in 739ce4b

@Schlagonia
Copy link

You will still need to add the strategist call the the IBaseStrategy interface https://github.com/sturdyfi/yearnV2-generic-lender-strat/blob/master/contracts/GenericLender/GenericLenderBase.sol

Its just a view funtion that returns an address

@sforman2000
Copy link

@Schlagonia fixed in b317e54

@Schlagonia
Copy link

Couple of small gas things:

no need to save this line to its own variable,

this for loop calls reserves[i] 3 times. Probably cheaper to declare an address reserve; outside the loop and set it during each loop to only read from the array once

@Schlagonia
Copy link

you can also remove all the instances of keep3r. Including state variable, setter function and modifier since this doesnt get harvested

@sforman2000
Copy link

@Schlagonia fixed in ffc8deb

@Schlagonia
Copy link

@Schlagonia fixed in ffc8deb

Sorry, meant you can get rid of the whole keeper modifier

@sforman2000
Copy link

Sorry, meant you can get rid of the whole keeper modifier

Understood, removed it in af4b126

@newmickymousse
Copy link
Author

LGTM

1 similar comment
@Schlagonia
Copy link

LGTM

@Schlagonia
Copy link

@sforman2000
Copy link

@Schlagonia @newmickymousse We updated the APR calculation in d0ad9d1 to fix the issue where the gas cost was too high during harvest.

@newmickymousse
Copy link
Author

new changes LGTM

@Schlagonia
Copy link

LGTM as well

@newmickymousse
Copy link
Author

@Schlagonia
Copy link

@storming0x
Copy link

storming0x commented Jan 23, 2023

Comment:

This version of the GenLenderBase has the old strategist role as management which latest version has replaced w management role since this is our default SMS Multisig for our current strategies

https://github.com/flashfish0x/yearnV2-generic-lender-strat/blob/f55c63ef3feaa03fb61e262ed4954db3e7f1cddc/contracts/GenericLender/GenericLenderBase.sol#L93

@iris112
Copy link
Member

iris112 commented Jan 23, 2023

Hi @storming0x
I have just replaced the role.
8b59c11

Regards.

@storming0x
Copy link

storming0x commented Jan 24, 2023

contracts/GenericSturdy.sol

Hey @iris112 i think the change should be vault.management() since the basestrategy interface doesnt have that method call from the repo yearn vaults.. see example

https://github.com/yearn/yearn-vaults/blob/97ca1b2e4fcf20f4be0ff456dabd020bfeb6697b/contracts/BaseStrategy.sol#L360

8b59c11

Sorry for the confusion i think the link i sent has a diff implementation of base strategy, so using vault.management() is a safer bet.

FYI im still reviewing the code so may come up with more things and comment here.

@storming0x
Copy link

storming0x commented Jan 25, 2023

Critical?

Although the initialize() method here

seems to repeat the same code, its potentially dangerous to leave this code without a lock once initialized, since it can be call over and over from any external actor and it shouldnt be the case for initialized calls to be available more than once.

Also if there are new versions of this, may add code that only needs to run once and forget that a lock guaranteeing only once execution is not in place, just another thing to juggle mentally which i think can be easily fix with a lock.

i suggest we use some time of lock to be sure the code in initialize is only executed once

@iris112
Copy link
Member

iris112 commented Jan 26, 2023

Hi @storming0x
I have just fixed the above issues.

1a4e108

Regards,
Thanks.

@Schlagonia
Copy link

Deployed Version with the most recent changes https://etherscan.io/address/0xaf363c4b4104c88ff7578b1d9898eaa1bdc0d257#code

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

No branches or pull requests

5 participants