Giter Club home page Giter Club logo

obol-splits's Introduction

Obol Logo

Obol Splits

This repo contains Obol Splits smart contracts. This suite of smart contracts and associated tests are intended to serve as a public good to to enable the safe and secure creation of Distributed Validators for Ethereum Consensus-based networks.

Disclaimer

The following smart contracts are provided as is, without warranty. Details of their audit can be consulted here.

Quickstart

This repo is built with foundry, a rust-based solidity development environment, and relies on solmate, an efficient solidity smart contract library. Read the docs on our docs site for more information on what Distributed Validators are, and their smart contract lifecycle.

Installation

Follow the instructions here to install foundry.

Then install the contract dependencies:

forge install

Local Development

To test your changes to the codebase run the unit tests with:

cp .env.sample .env
forge test

This command starts runs all tests.

NOTE: To run a specific test:

forge test --match-contract ContractTest --match-test testFunction -vv

Build

To compile your smart contracts and generate their ABIs run:

forge build

This command generates compilation output into the out directory.

Deployment

This repo can be deployed with forge create or running the deployment scripts.

Goerli Network Contracts

Contract Type Address
OptimisticWithdrawalRecipientFactory 0xe9557FCC055c89515AE9F3A4B1238575Fcd80c26
OptimisticWithdrawalRecipient 0x898516b26D99d0F389598acFcd9F115Ab8184Fe3
ImmutableSplitControllerFactory 0x64a2c4A50B1f46c3e2bF753CFe270ceB18b5e18f
ImmutableSplitController 0x009894cdA6cB6d99866ca8E04e8EDeabd625712F
ObolLidoSplitFactory 0x40435F54cc57943C727d8f856A52d4E55501cA8C
ObolLidoSplit 0xdF46B2f36ffb67492A73263Ae3C3849B99DA9967

Sepolia Network Contracts

Contract Type Address
OptimisticWithdrawalRecipientFactory 0xca78f8fda7ec13ae246e4d4cd38b9ce25a12e64a
OptimisticWithdrawalRecipient 0x99585e71ab1118682d51efefca0a170c70eef0d6

Holesky Network Contracts

Contract Type Address
ObolLidoSplitFactory 0x934ec6B68cE7cC3b3E6106C686B5ad808ED26449
ObolLidoSplit 0x22bdC6609de39E569546184Bff4ba4716d34fEBd
OptimisticWithdrawalRecipientFactory 0x7fec4add6b5ee2b6c1cba232bc6db754794cb6df
OptimisticWithdrawalRecipient 0x8c55787F913A62a41A6CB7943e91827a02beB663

Mainnet Contracts

Contract Type Address
OptimisticWithdrawalRecipientFactory 0x119acd7844cbdd5fc09b1c6a4408f490c8f7f522
OptimisticWithdrawalRecipient 0xe11eabf19a49c389d3e8735c35f8f34f28bdcb22
ObolLidoSplitFactory 0xA9d94139A310150Ca1163b5E23f3E1dbb7D9E2A6
ObolLidoSplit 0x2fB59065F049e0D0E3180C6312FA0FeB5Bbf0FE3
ImmutableSplitControllerFactory 0x49e7cA187F1E94d9A0d1DFBd6CCCd69Ca17F56a4
ImmutableSplitController 0xaF129979b773374dD3025d3F97353e73B0A6Cc8d

Versioning

Versioning of releases to this repo has not been implemented.

obol-splits's People

Contributors

cosminobol avatar f1lander avatar jules avatar oisinkyne avatar samparsky avatar thomasheremans avatar xenowits avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

obol-splits's Issues

Create `core` and `periphery` licenses for this repo.

Problem to be solved

We want to make this repo public soon. We will want people to interact with our contracts, particularly our factories. However, we will not want people wholesale copy/pasting our IP but with e.g. their fee splitter configurations built in instead.

Proposed solution

I think we copy the uniswap approach, where they business source licenses the core contracts, and they MIT licensed the periphery/integration contracts.

In our case:

  • The Factory would be BSL
  • NFT contract would be MIT

Add an ENS reverse resolution (primary) name to our factory contract

Problem to be solved

The Ethereal Ventures security assessment flagged that we should make use of ENS names to make our launchpad harder to phish.

During setup, users should only sign one transaction via the Launchpad - to a contract located at an Obol-held ENS (e.g. launchpad.obol.eth). This contract should deploy everything needed for the cluster to operate, like the withdrawal and fee recipient contracts. It should also initialize them with the provided reward split configuration (and any other config needed).
Rather than using an NPM library to supply a factory address or JSON artifacts, this has the benefit of being both:
Harder to compromise: as long as the user knows launchpad.obol.eth, it’s pretty difficult to trick them into deploying the wrong contracts.
Easier to validate for non-technical users: the Obol contract can be queried for deployment information via etherscan. For example:

Proposed solution

Similar to the Obol token contract, we need to claim and transfer the admin rights to the ens reverse resolver for the factory contract.

This will allow the new owner to set the reverse resolver of the factory contract to launchpad.obol.eth

Goerli distributed validator running in swell smart contracts

Problem to be Solved

we are preparing for M1. As part of this we want to know if M1-swell can go ahead. To do that, we should run a swell validator on their goerli testnet deployment

Proposed Solution

Activate a testnet validator in swell's testnet smart contracts with their operators.

Fungible DV Prototype

To Do

tl;dr, we test using ERC1155 to make validators instead of NFTs. Fresh tranche for each new Obol Cluster

Create forge cast commands to interact with the waterfalls

Problem to be solved

When we deploy the factory, we want to make it easy for people to use it

Proposed solution

Deploy the factory.

Document the forge/foundry/cast command needed to call the createWaterfall type functions.

Outline how to create different waterfalls with different SplitWallets underneath.

add `DepositEvent`

  • contract should emit a DepositEvent event when deposit is made

Solution:

  • Add a event type:
    /// @notice A processed deposit event.
    event DepositEvent(
        bytes pubkey,
        bytes withdrawal_credentials,
        bytes amount,
        bytes signature
    );

Activate DV Script

------- Needs refinement
We need forms of scripting to activate deposits, we will also need to integrate it into deployments of obol-manager-contracts (in future waves we should also pre-deploy WithdrawalRecipient contracts to specific addresses and give them to workshop teams so we can validate that our withdrawal contracts can work).
Maybe even with foundry scripts to get the hang of them

Document the 0x04 withdrawal contract exit in a design doc for Ethereum Foundation

Problem to be solved

We are collaborating with the Ethereum Foundation team (Mikhail Kalinin and Jim McD) on ethereum/EIPs#7002 to Add a cross-layer method to trigger validator exits from the execution layer.

Proposed solution

We should spend a significant amount of time:

  1. observing and reviewing Ethereum Foundation to get EIP-7002 approved,
  2. to observe if/when client teams (such as Lighthouse, Nimbus, etc.) will implement the changes,
  3. to document in a design doc how we aim to propagate the changes through a contract to Charon.
  4. Also BD should inform Lido, Stakewise, etc. how the new "exit validator" will work.

It affects Contracts project, because it will impact the exit smart contract process.

0x04 = withdrawal prefix

Next steps

  1. Foundation approval
  2. exit contract design doc to document how to stop doing manual exit, trigger a notification being intercepted by a client (if up-to-date) and then Charon.

side notes: if the client is not up-to-date, will not be able to listen to the main chain anymore.

@corverroos FYI

Acceptance Criteria

(to be implemented in a separate ticket)
When a validator exits a cluster
And Ethereum foundation approved EIP-7002
And the exit contract is able to handle the request and propagate it
And a client is able to handle the request
And Charon is able to handle the request
Then the validator should be able to exit the cluster automatically

Support rebasing tokens

Lido node operator rewards are issued in stETH. stETH is a rebasing token. The current contract design doesn't support a rebasing token.

monitor Splitter and Factory deployments on Dune

🎯 Problem to be solved

There is a need to monitor our Splitter and Factory deployments on testnet/mainnet and integration with various protocols on Dune. Analyzing these elements is essential but often challenging because of the immense amount of data and the various metrics that need to be presented.

🛠️ Proposed solution

To address the problem, the following steps can be taken to build a dashboard to monitor Splitter and Factory deployments and integration with various protocols:

  1. Identifying the Metrics: Determine what to analyze and the metrics to present.
  2. Utilizing Pre-Built Dashboards: Leverage existing community-contributed guides and dashboards and analyze existing metrics and trends
  3. Creating Custom Dashboards: Utilize Dune's platform to create custom charts and dashboards using plain SQL, leveraging decoded Ethereum smart contract data
  4. Connecting and Integrating Protocols: Consider the mix of on-chain events happening and ensure integration trends are incorporated into the dashboard.
  5. Sharing and Collaborating: Once the dashboard is complete, share the work in communities, get feedback, and make necessary improvements.
  6. Continuous Monitoring and Updates: Keep the dashboard up-to-date and adjust as new information and changes occur within the web3 data analytics space.

Splitter contracts fork

We are aiming to fork the splitter contracts and include the functionality listed below

  1. Add distributor-gated splits
  2. Add the ability to create custom Split wallets
  3. Rewrite tests in Solidity

Script Development for Analysis of Testnet and Mainnet Withdrawals

🎯 Problem to be solved:

We lack concrete data on the distribution of withdrawals from both the testnet and mainnet, making it challenging to identify practical threshold values for classifying withdrawals as rewards or principal based on the validator status. This lack of empirical data hinders our ability to fine-tune and optimize our "Heuristic Threshold Reward Classification" system.

🛠️ Proposed solution:

The proposed solution is to create a script that analyses withdrawals from both the testnet and mainnet. The script will classify withdrawals as either rewards or principal based on the validator status. This analysis will provide us with real-world numbers, which we can use to identify practical threshold values for our heuristic classification system. This data-driven approach will allow us to improve the accuracy and efficiency of our classification system.

@samparsky to suggest a threshold based on knowledge and analysis and give some reasons for it.

An oracle-free mev-sharing solution spike

Problem to be solved

A service we would like to offer DVs is the ability to opt into a pooling fee_recipient address. It must be fair, equal, and ungameable. It should not have a dependence on a trusted off chain party telling the smart contract who has contributed what/what to distribute to everyone.

Proposed solution

Make a spike doc where we gather examples such as rocketpool and smoothly and lido etc. See if we could do something with like 4626 vault contracts, or 0xsplits contracts. Work with Oisin on selecting a PoC to make after this exploratory research is complete.

Withdrawal Beneficial Owner Contract

Problem to be solved

We want to add a fee cut to the launchpad sooner rather than later to get people used to it

Proposed Solution

Create a withdrawal beneficiary contract that is able to distribute stake and rewards to participants in a DVT cluster

Out of scope

Hooking this contract up to the launchpad. Just need to build + test in foundry + document how to generate abis for the launchpad

Single reward splitter, multiple validators

Problem to be Solved

We want multiple waterfalls to point at a shared reward splitter contract, so you can reward split e.g. 10 validators.

Proposed Solution

Make a factory contract in this repo that can deploy minimal proxies that behave as waterfalls.

Deploy 10 withdrawal recipient contracts to Goerli for use in EthBerlin

Problem to be Solved

For upcoming practice attack nets, we need to start deploying different WithdrawalRecipient flavours to testnets for us to use as withdrawal credentials for new validators.

Proposed Solution

Deploy 3 copies of Arbiters withdrawal recipient beneficial owner
Deploy 3 copies of Oisins withdrawal recipient ownable
Deploy 4 copies of Will from 0xSplits waterfall split

Get all three of these into this repo to make it happen

Verify them on etherscan ideally (Oisin ran into a bug trying it)

Give the 10 addresses to thomas for private key creation. He will make 10 standard validator deposits + private keys with the normal staking-deposit-cli, one for each of them. He will then activate them with 320 eth from oisin to get them in the validator queue with the intention of them being live by ethberlin.

We will use charon create cluster --split-existing-keys on the day to shard these into as many ENRs + shares as we have hackathon participants. We will load those in to everyone's nodes and then let them attack each other and their withdrawal recipients even.

Do a design doc/write up about Lido V2 Registry

Problem to be Solved

Lido have released a design doc for a new modular operating registry

Proposed Solution

Let's parse it, do a presentation and Q&A about it on ADC, and lets see if there are any ways we can make it better for DVs.

Design Doc - Claiming from multiple clusters

Problem to be solved

As we understand the implementation today, Obol publicgoods or any operator in multiple clusters would have to claim from every cluster.

The goal of this Design Doc is to explore our options for claiming multiple clusters rewards. This could be accomplished via alterations/additions to the set of contracts or a programmatic solution for claiming.

Heuristic Waterfall Contract Test Suite

🎯 Problem to be solved

There is a need to modify the waterfall implementation to allow for values below a certain threshold to flow to tranches. This will enable setting a low fee threshold that can go to the reward address first, allowing a node operator to receive a cut of CL rewards without exiting the validator(s). Therefore, the problem to be solved is to test this enhanced functionality to accommodate a more flexible reward distribution system.

🛠️ Proposed solution

  1. Smart Contract Testing: Implement a comprehensive test suite to thoroughly test the heuristic waterfall contract and factory with the new fee threshold feature. The test suite should cover various scenarios, edge cases, and possible exceptions to ensure the solidity of the contracts.

  2. Gas Optimization: Carefully review the contracts' gas usage during testing and optimize the code wherever possible to reduce transaction costs and improve overall performance.

  3. Documentation: Provide clear and comprehensive documentation for the test suite, detailing the purpose of each test case, the expected outcomes, and any relevant instructions for developers to follow when running the tests.

By implementing the proposed solution and conducting thorough testing, we can ensure a robust and efficient heuristic waterfall contract and factory, capable of handling rewards distribution with a configurable fee threshold.

Spike 0xsplits-swapper

Problem to be solved

LSPs want to pay us in LSTs, we want to receive Eth or WETH only.

Proposed Solution

Deploy https://github.com/0xSplits/splits-swapper/ on goerli (or interact with their deployment if they have one wired up).
See how we can dictate the slippage/exchange price of a swap.
See which LSTs don't trade on uniV3, how might we make this work with this issue?
If a chainlink oracle based swapper would work better, provide feedback to Will

Goerli Stader Distributed Validator

Problem to be Solved

We are preparing for M1. As part of this we want to know if M1-stader can go ahead. To do that, we should run a stader distributed validator on their goerli testnet deployment.

Proposed Solution

Activate a testnet validator in staders testnet smart contracts with their operators.

PoC a waterfall with eager-scraping of rewards

Problem to be solved

Currently we play the cautious route, and only allow rewards to flow from a waterfall to a splitter once 32 eth has been paid out to the principal. We can instead set a low threshold of fees that can go to the reward address first, allowing a node operator to get a cut of CL rewards without having to exit the validator(s)

Proposed solution

Modify the waterfall impl to allow for value below a certain threshold to flow to tranche 2 rather than tranche 1.

Review Heuristic Threshold Reward Classification

🎯 Problem to be solved

The current waterfall contract classifies the first 32ETH worth of contract balance as principal, leading to operators practically receiving rewards only upon validator exit. Also, operators don't receive any rewards if the full principal amount of 32ETH isn’t withdrawn. The document proposes a “heuristic threshold” to classify balance as rewards vs principal at any point during the lifetime of a validator.
This is how withdrawal payments work. Beacon chain staking rewards for validators with a balance over 32 ETH are automatically “withdrawn” to the execution layer every few days.

🛠️ Proposed solution

The doc primarily aims to establish the simple case of a single smart contract for a single validator, although the proposal could also be applied to a batched approach where multiple validators in the same cluster all use the same withdrawal address.
The proposal involves picking a “heuristic threshold value” that is reliably less than principal withdrawals but greater than EL and CL rewards. The smart contract would expose a classifyRewards function that would classify any “unclassified balance” as either “principal or rewards” based on that threshold. The total amount of previously distributed principal should be tracked, if the total principal has been distributed (32ETH), then all remaining principal get reclassified as “reward”.

Implications

The proposal has implications for operators who are incentivised to call classifyRewards before the balance reaches the threshold. The document also notes that the gas cost of the classifyRewards should be insignificant. However, operators will receive any rewards accrued before a full 32ETH exit (slashing or voluntary). Large unicorn MEV based EL rewards above the threshold will be classified as principal, so will only be distributed as rewards on validator exit.

https://docs.google.com/document/d/1K86PFqDf6vZPwBnaEmd6stN8-wz5x4xa3cf1i1u1oj8/edit#heading=h.mssb0822zapb

Fractionalised DV prototype 1

Problem to be solved

We want to explore the idea of fractionalising DVs, and also making them partially fungible. However, considering we are already in the business of spreading risk across operators, we do not want to spread risk across clusters too, as that could cause contagion and is a bit of a legal bad idea too.

So we want to explore partial fungibility and fractionalisation of DVs over the coming weeks, and we will user test these two concepts, and see which there is more demand for, and which makes more sense on a gas optimastion front too.

Proposed solution

This ticket is to use EIP 4626 to make a fractionalisation mechanism for a single cluster of operators.

How I think this will work is:

  • We create an Operator Auth role. During contract deployment we pass an array of eth addresses that get this Operator role.
  • These operators can add Deposit Data details to the DepositRegistry. This is an array of unactivated validator deposit files. We verify that the withdrawalAddress for this deposit is this contract (see this for exact formatting of withdrawal credentials field)
  • We expose a method called deposit
    • It checks that this.balance > 32
    • It checks that DepositRegistry.length > 1
    • If both checks pass, it takes the deposit object, removes it from the DepositRegistry and sends the data in the object with a message.value 0f 32 eth to this contract function (the official deposit contract)

The above is just the activation logic, next we need to do the user facing accounting logic, this is where ERC4626 comes in.

Firstly, it is based on ERC20s, so we will need to import the Weth10 contract and will need to unwrap weth to deposit.

When someone sends us Weth, we issue them LP tokens. Later, we will implement withdrawals, and burning of LP tokens, but there is no code for that yet. We can start to test that functionality with forge's prank command, which allows arbitrary balance modifications.

Not yet outlined

How fees to operators and Obol are taken out. Likely we will depend on an 0xSplits contract that takes like 2%, half to the operators half to obol, but TBC

Function Development for Theoretical Sweep Calculation Based on Validator Count

🎯 Problem to be solved:

Currently, we lack a systematic and efficient way to calculate the maximum theoretical sweep a validator could receive. This calculation is important to understand the potential reward distribution and to make informed decisions regarding our reward allocation policies.

🛠️ Proposed solution:

We propose to create a function that calculates the maximum theoretical sweep a validator could receive based on the total validator count. This function should be able to provide a deterministic number, thus allowing us to anticipate the potential rewards for a given validator. By having this function, we can better manage our reward distribution strategy and ensure fair allocation of rewards based on the validator's contribution.

Create a proposal for the OP-stack leader election RFP

Problem to be solved

Optimism have sketched out what they think is the pre-work needed to allow OP chains to explore differing leader(sequencer) selection schemes. They have documented it here ethereum-optimism/ecosystem-contributions#63

We need to make a proposal to them by June 28th if we want to be considered. CC @boulder225

Proposed solution

I do not have a proposed solution yet, I am hesitant for us to commit to doing the work to make the optimism stack ready for leader election experimentation, but we should at least make a spike doc like our previous op-dst work (CC @xenowits @dB2510 ) but with the context given to us in the above.

add required checks in `deposit()` function

  • add require statements to check validity of input to deposit() method
  • ex:
// Extended ABI length checks since dynamic types are used.
require(pubkey.length == 48, "DepositContract: invalid pubkey length");
require(withdrawal_credentials.length == 32, "DepositContract: invalid withdrawal_credentials length");
require(signature.length == 96, "DepositContract: invalid signature length");

// Check deposit amount
require(msg.value >= 1 ether, "DepositContract: deposit value too low");
require(msg.value % 1 gwei == 0, "DepositContract: deposit value not multiple of gwei");
uint deposit_amount = msg.value / 1 gwei;
require(deposit_amount <= type(uint64).max, "DepositContract: deposit value too high");
  • Above checks taken from original deposit contract here

Tokenise ownership of a waterfall contract

Problem to be solved

We are working on our waterfall contracts and making them multi validator. Listening to bankless' ep on MiCa, they say DeFi and NFTs are carved out of the regs, so if we're going that route, lets stay away from dollarised APR products in the near term and go to 'DeFi' market with NFTs of DVs, that we feed into products that favour showing eth denominated everything.

With that in mind, when creating waterfall contracts, lets mint NFTs that 'own' them (I think 0xSplits have code for this), and see if we can have one master ERC1155 (or 721) that issues all of these from, with waterfalls taking fees under the hood.

Proposed solution

Design an ERC1155, 721, or similar contract, that can wrap and work with our waterfall factory.

A user should be able:

  • To be minted NFTs in return for deploying waterfall contracts (do we need to wait until validator deposit to mint?)
  • to call a claim() like method, that updates the related waterfall contract to push funds sitting in it out to principal and split, to update the splitter contract to push the rewards onwards to the split main contract, and to claim whats in split main, and what is in the principal address of the waterfall. e.g. I

Open Design questions:

  • We now have 1 splitter, many waterfalls as a primary design pattern. We will set fee_recipient = splitter, not any of the waterfalls. So pre-exit, execution rewards are going straight to the splitter. How does the nft holder claim that split balance in an ongoing manner versus the waterfall contract claim? We should probably separate them into two separate methods to save gas, one that just updates the splitter and pulls what they've accrued in split main. And another one that calls the waterfall contract first to push funds from there (balance skimming rewards normally, principal + consensus rewards once). But two txs to claim is bad ux, and integrations might not like making to eth_calls.

Test if rewards are properly distributed using the current Obol integration with Lido V2 contract DV on goerli

Problem to be solved

Lido liquid staking wants to adopt Obol technology, and in the meantime, they already released V2 which has a modular architecture. Lido would give Obol control of a staking module. Obol wants to distribute rewards using the new Lido version.

Proposed solution

  • To check out smart contract integration with Lido for the point of reward distribution.
  • Write E2E testing for Lido v2 Splitter contract integration

Acceptance Criteria

Given Obol contract is fully integrated with Lido V2 contract
When Obol contract receives a stake ETH from Lido
And there is distribution rewards from Lido V2
Then the E2E test can verify that Obol contract is able to distribute the rewards to the recipients

Expected Lido V2 response: this story covers only the happy path, without considering any corner cases. We should ask Lido what could go wrong on their side, to handle gracefully any unknown behaviours

Scope: this story covers only the contract side, without launchpad/user interaction.

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.