Giter Club home page Giter Club logo

liquid-collective-protocol's Introduction

Liquid Collective Protocol

tests mythril lint license

This repository contains the Liquid Collective Protocol's smart contracts.

Liquid Collective is a liquid staking protocol designed to meet the needs of institutions, built and run by a collective of leading web3 teams.

Liquid Collective enables users to stake ETH and mint LsETH. The LsETH liquid staking token evidences legal and beneficial ownership of the staked ETH and any network rewards that the staked ETH accrues, minus any fees and penalties.

Useful Links

Deployment Addresses

Contract Mainnet Holesky
TLC 0xb5Fe6946836D687848B5aBd42dAbF531d5819632 0x1dA1B892575dc5fABbef28FA0F62fE302ED39E83
River (LsETH) 0x8c1BEd5b9a0928467c9B1341Da1D7BD5e10b6549 0x1d8b30cC38Dba8aBce1ac29Ea27d9cFd05379A09
OperatorsRegistry 0x1235f1b60df026B2620e48E735C422425E06b725 0xCb8641aF17e19976245bEB68CD50f61c5779b294
Oracle 0x895a57eD71025D51fe4080530A3489D92E230683 0xc8D639f014a78B1cEc17761BFD9E8c80919efbc6
Allowlist 0xebc83Bb472b2816Ec5B5de8D34F0eFc9088BB2ce 0x5C783DCD596dad2bDe930f22C3684E77E25b6436
CoverageFund 0x32aac358b627b9feaa971cc33304027a41e49a81 0x8eeaca6f8964771d4e50f899a06f527c2affe15c
Withdraw 0x0AFd81862eEA47322Cf85Db39D3D07e8A3c25154 0xAaF99F2F0C47EF32AB9B5aa3e117c9190b37Ff88
ELFeeRecipient 0x7D16d2c4e96BCFC8f815E15b771aC847EcbDB48b 0x4E44868856A26F4cbB431cC144318D4E7F39a585
RedeemManager 0x080b3a41390b357Ad7e8097644d1DEDf57AD3375 0x0693875efbF04dDAd955c04332bA3324472DF980
WLSETH n/a 0x21ae523bf67C81c8e4F640d8f76F9c7B77eCc0bf

Security

If you're interested in learning more about Liquid Collective security processes, including security audits and the protocol's vulnerability disclosure policy, see: Liquid Collective Security

Contributing

For guidance on setting up a development environment and how to make a contribution to Liquid Collective, see the contributing guidelines.

Licensing

The primary license for Liquid Collective is the Business Source License 1.1 (BUSL-1.1), see LICENSE. However, some files are dual licensed as indicated in its SPDX header.

liquid-collective-protocol's People

Contributors

mortimr avatar flanagansteve avatar iamsahu avatar nmvalera avatar cebidhem avatar 0xvv avatar mischat avatar mattketmo avatar

Stargazers

Aleksey116 avatar Petar Radovic avatar Taeguk Kwon avatar ahmed mossati avatar 周星星 avatar  avatar  avatar  avatar  avatar  avatar Matt Leisinger avatar dkf avatar  avatar pwnh4 avatar  avatar  avatar MitkoDeSofia avatar

Watchers

Matt Leisinger avatar Cattani avatar Julien Boulanger avatar Romain Guichard avatar David Turnbull avatar  avatar

liquid-collective-protocol's Issues

HAL-08: IGNORED RETURN VALUES

Return values from ERC20 calls are ignored.

Solution

As recommended by Halborn, we should check the return values and assert everything went fine (not expect them to revert in case of an issue, even if most will do)

HAL-04: MALICIOUS OWNER CAN ADD AN OPERATOR WITH EXISTING NAME

We are using the name as one of the unique IDs in the system to identify operators. Operators could have the same reward address, it wouldn’t give them any advantages as rewards are computed depending on the number of active validators per operator.

Solution

Add a utility to allow operators to change the name that is registered that also checks if the new name is not already in use.

Release v0.1.0

Description

Go through the release process for v0.1.0.

Allow to configure allowlist checks (minting and/or transfer)

Description

We need to check on deposit and not on transfer

Acceptance Criteria

  • We could transform permission from a boolto and ùint256`and use each bit a specific permission over the contract
  • Move allowlist manager into a separate contract being hooked by River contract
  • Enable multiple allowers

How to handle variations in the Shares storage slot and _assetBalances?

A common pattern we employ to manage balances is to fetch the lsETH balance via a call to balanceOf, then move all or a fixed portion of those funds to another wallet.

Assuming we know we have full control during the whole history of the from and to addresses for a given Transfer event, how do you manage the changes in time of the ratio IRiver._assetBalance() / Shares.get()?

I'm scared to be stuck in a situation where we request a balance a couple of weeks in advance for a transfer, then we execute the transfer but the above ratio has changed and we don't execute the full transfer/transfer too much funds.

DAO integration

Description

Governance

  • Proxy Admin: that can handle the upgrade of the contracts (River + Oracle+ Withdrawal Contract)
  • System Admin
  • setting the Allowers
  • setting the Oracle address
  • adding Node Operators
  • setting Node Operators limits
  • add Oracle members

Acceptance Criteria

  • Look into Uniswap governance contracts

HAL-09: LACK OF ZERO ADDRESS CHECKS

A lot of address SSTORE are not checking if the value is not zero.

Solution

We can add these checks for extra safety but it won’t really solve the issue that an invalid value could be used (address(0) is just one in the 2^256 - 1 possible errors)

HAL-07: MISSING REENTRANCY GUARD

No reentrancy guard has been used on methods that have external calls as state modifications are always performed before the calls.

Solution

As recommended by Halborn, to add extra safety around these methods, the reentrancy guard by openzeppelin could be used.

Batching allowlisting of stakers

Description

Send a single tx to allow multiple stakers at once

Acceptance Criteria

  • Update current method to allow(addresses []address)
  • Max should be the gas limit

HAL-03: DIVISION BY ZERO

Possible division by zero exists in _onEarnings . If _assetBalance() * BASE equals _amount * globalFee, then a division by zero occurs.

Solution

As recommended by Halborn, check if the denominator is 0, and return 0 if it’s the case.

Generate and host gas reports

Description

Generate and host a report of gas consumption for every smart contract methods

Acceptance Criteria

  • set 2 independent test suites for (likely the simplest is to name test with a keyword like Fuzz)
    • base test with gas estimation
    • fuzz test
  • Approach: to be discussed with @mortimr
  • Where to host it?

Update token format from aToken to cToken

Description

Acceptance Criteria

  • Make balanceOf(acc address) to be share[acc]
  • Add abalanceOfUnderlying(acc address) method to return sharesOf() * ratio (the worth of all shares). Double check for the name on Coumpound token and have a look to ERC-4626 for view methods. Point of consciousness: we should not rely completely on a unproven standard
  • Let's not merge PR in a first stage

Reporting MVP

In this MVP we will provide an API for retrieving the following data, and simple demo/reference dashboard for exposing it

User stories

As a staker, I want to know

  • lsETH balance & rewards now and over time
  • My allowlist status + lastUpdated timestamp (1)

As a protocol admin, I want to know:

  • The history of the Oracle reports
  • Total amount of ETH at each stage of the deposit lifecycle
  • Deposit breakdown per referrer (2)
  • Get the free/funded validator keys
  • Total number of wallets that have deposited, are in allowlist

As a distribution partner, I want to know:

  • The allowlist status of a given user (see 1 above)
  • How much volume I have referred (see 2 above)

Out of scope for this iteration:

  • Node operators performance data
  • Market data (eg lsETH<>ETH liquidity)

Data source

The goal of this MVP is to confirm that this set of data, delivered via a REST API, will be sufficient for our different stakeholders

The data will get sourced from TheGraph Hosted version for the MVP. Once we have confirmed this is the data we need, we can "industrialise" the data collection, either with our own subgraph we run or our own data aggregator.

Further reading

Notes: https://www.notion.so/figmentnetworks/Data-services-8b8709e13eb24f4db81e320fdf5add0e
Subgraph: https://thegraph.com/hosted-service/subgraph/mattketmo/crymeariver?query=List%20Users

cc @leisinmr @flanagansteve let me know if any Qs!

Generate and host Mythril reports

Description

Configure Mythril to run in CI/CD, generate reports, and break CI/CD in case of vulnerability detection

Acceptance Criteria

  • Mythril command generate a report in a format that can be hosted (e.g. HTML)
  • Store report as a GitHub artifact
  • Find the best configuration

Migrate all docs to Gitbook

One source of truth for docs -- Gitbook -- rather than a mix of Gitbook and google docs.

And we will gate these docs behind auth

fee recipient revamp

Problem

Currently, the fee recipient holds funds that get integrated inside River whenever someone calls the compound() method. This method is unprotected so anyone could call it and it isn't an issue from a security pov, but it becomes an issue from an accounting pov as it triggers the onEarning callback that will send funds to the treasury and operators.

Solution

The fee recipient compounding logic should be triggered upon the oracle report submission. Whenever quorum is met on the Oracle, a callback will trigger onEarning with the delta between previous and new total balance. We should also add the fee recipient funds there. To do this, we would add a new payable method to River that the fee recipient could call to send the funds without triggering any token minting logic.

Untitled

  • pullELEarnings is a protected method that is only callable by River
  • sendELEarnings is a protected method that is only callable by the Fee Recipient
  • onEarnings will be called with the sum of earnings from the setBeaconData and sendELEarnings() calls

Edits required

  • Add sendELEarnings and getELFeeRecipient to River
  • Add ELFeeRecipient address to River construction
  • Add pullELEarnings to ELFeeRecipient
  • Remove compound from ELFeeRecipient
  • Edit the setBeaconData logic to also include ELFeeRecipient.pullELEarnings call

HAL-05: SINGLE-STEP OWNERSHIP CHANGE

To change the system admin, a simple on-step method can be called.

Solution

As recommended by Halborn, set a two-step process where we first propose a new admin from the admin account and the target new admin has to accept the ownership. This would prevent sending the administration to an invalid account that is not able to perform transactions.

Enable withdraw of buffered ETH

Description

As deposits happen, we buffer ETH on the River contract, an admin regularly calls the depositToConsensusLayer contract method to trigger the actual deposits of the buffered ETH to the official deposit contract and subsequently get new validator keys added to the validator set.

This is a proposal to use buffered ETH to enable burning lsETH in return for some ETH at the current internal exchange rate

Rationale

  • may help maintain the peg between the external exchange rate on exchanges and the internal exchange rate Example if a de-peg happens then a straightforward arbitrage consists in buying lsETH with ETH on an exchange at a lower rate and then burning lsETH for ETH on the River contract at a higher rate
  • validator keys are not systematically added to the validator set for every ETH being staked, by doing so
    • we put less keys in the activation queue which is currently crowded with a wait time of around 10-15 days
    • we do not increase the volume of lsETH when there is actually a demand for ETH. This is a driver to reduce the total volume of the pool, which the ecosystem probably will well receive

Extra comment

  • Is this possible on other staking pools
    • Lido: No
    • RocketPool: Yes
    • Others (to be assessed)

Fix forge test error

Currently, forge is not able to run tests on the latest version and fails with this error

installing solc version "0.8.10"
Successfully installed solc 0.8.10
Error:
   0: Solc Error:

Location:
   cli/src/cmd/utils.rs:40

Backtrace omitted.
Run with RUST_BACKTRACE=1 environment variable to display it.
Run with RUST_BACKTRACE=full to include source snippets.

This is probably due to some layout issue on the repository making forge unable to compile and run test.

To do

Remove hardhat-foundry and use foundry directly + fix layout issue

Provide a mechanism to perceive Execution Layer fees

Description

With the upcoming Ethereum Merge, validators will be the beneficiary of the Execution Layer fees (transaction fees + MEV fees).

We need to add a mechanism to River to collect those fees. A reasonable approach seems to deploy another contract that will be the recipient of the transaction fees, let's name it ELFeeRecipient (to be discussed further). Then Node Operators will be requested to configure their validator to the this contract.

Acceptance Criteria

  • implement ELFeeRecipient contract
  • update River contract to collect fees from the ELFeeRecipient

Extra Information

Redeploy contracts

Acceptance Criteria

  • Set allowlister
  • Set oracle operator
  • Add Node Operators
  • Allow depositors
  • Create a document with all accounts to be added

Discussion: Should we revert the hardcoded hex for constants?

Issue #7 suggested that we hardcode constants in unstructured storage to save deployment cost. The logic was that on deployment, constants like:

bytes32 internal constant ORACLE_MEMBERS_SLOT = bytes32(uint256(keccak256("river.state.oracleMembers")) - 1)

Would need some gas for the keccack256() as well as each cast operation. However, it appears that solc, under the hood, actually performs these operations at compilation time and saves the const in the bytecode. This means that replacing the above with the less readable:

/* Hardcoded hex is: bytes32(uint256(keccak256("river.state.oracleMembers")) - 1) */
   bytes32 internal constant ORACLE_MEMBERS_SLOT =
       hex"c4aba040293e5848600dd7b64a390db880c4a70937c23383e6c5b6619689863a";

Does not actually save any gas

Should we, therefore, revert this change and bring back the computation for each const?

Referrals

Description

Remove referrer input from the deposit()

Acceptance Criteria

Emit events on depositToConsensusLayer

Description

Acceptance Criteria

  • Emit event for every key deposited to the official deposit contract
  • Emit event at the end of depositToConsensusLayer() with total keys and value deposited

Make slots internal and hardcoded

Description

Acceptance criteria

  • make all slot declaration ìnternalinstead ofpublic`
  • hardcode slot value, letting a comment about how the value is computed

Example

  /* keccak256("StakingContract.admin") */
bytes32 internal constant ADMIN_SLOT = hex"fbeda9bc03875013b12a1ec161efb8e5bf7e58e3cec96a1ea9efd3e264d26e64";
    ```

Avoid leaking data by relating a staker address to an allowlister address

Description

In the current format, it is publicly visible on-chain what accounts have been allowed by which allowlister. By knowing who is behind an allowlister address and tracking all staker address activity you can do some financial assessment.

We should avoid this

Acceptance Criteria

  • propose an approach

Discussion: What license are we using and why?

Extremely low priority question, but - Some files, such as AllowListManager.1.t.sol and the other tests, use:

//SPDX-License-Identifier: MIT

While others, like River.1.sol, use:

//SPDX-License-Identifier: BUSL-1.1

Is there a reason for different licenses between tests and other contracts? Or would we like to commit to one and use it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.