Skip to content

Commit

Permalink
Lido Tier 1 Integration NO data (#401)
Browse files Browse the repository at this point in the history
* refactor: lido.go

* feat: get NO ID by reward address

* style: adjust format

* refactor: contract setup logic

* refactor: Adjust tests for nodeOperator

* test: add Fuzz test for NodeID

* feat: Add keys info

* feat: Add bonds info

* feat: Get non-claimed rewards

* feat: generate contracts Go code

* feat: remove contracts go code

* doc: update documentation

* feat: add generated contract files to .gitignore

* refactor: adjust error message

* refactor: reduce search complexity for rewards

* refactor: Handle Contract deployed addresses

* test: Adjust test cases

* test: Add unit tests

* test: remove additional logs

* feat: remove SigningKeys function

* refactor: Adjust error messages

* feat: Remove proof parameter from Rewards method
  • Loading branch information
khalifaa55 authored Aug 13, 2024
1 parent aef5ceb commit 01fcb11
Show file tree
Hide file tree
Showing 26 changed files with 1,056 additions and 5,735 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ jobs:
- name: Install mockgen
run: make install-mockgen

- name: Generate mocks
- name: Install abigen
run: make install-abigen

- name: Generate mocks and contracts
run: make generate

- name: Check go mod status
Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@ build/sedge
courtney/

mocks/

internal/lido/contracts/csaccounting/CSAccounting.go

internal/lido/contracts/csfeedistributor/CSFeeDistributor.go

internal/lido/contracts/csmodule/CSModule.go

internal/lido/contracts/mevboostrelaylist/MEVBoostRelayAllowedList.go
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ run-cli: compile ## run cli

generate: ## generate go files
@go generate ./...
@abigen --abi ./internal/lido/contracts/csmodule/CSModule.abi --bin ./internal/lido/contracts/csmodule/CSModule.bin --pkg csmodule --out ./internal/lido/contracts/csmodule/CSModule.go
@abigen --abi ./internal/lido/contracts/csfeedistributor/CSFeeDistributor.abi --bin ./internal/lido/contracts/csfeedistributor/CSFeeDistributor.bin --pkg csfeedistributor --out ./internal/lido/contracts/csfeedistributor/CSFeeDistributor.go
@abigen --abi ./internal/lido/contracts/csaccounting/CSAccounting.abi --bin ./internal/lido/contracts/csaccounting/CSAccounting.bin --pkg csaccounting --out ./internal/lido/contracts/csaccounting/CSAccounting.go
@abigen --abi ./internal/lido/contracts/mevboostrelaylist/MEVBoostRelayAllowedList.abi --bin ./internal/lido/contracts/mevboostrelaylist/MEVBoostRelayAllowedList.bin --pkg mevboostrelaylist --out ./internal/lido/contracts/mevboostrelaylist/MEVBoostRelayAllowedList.go


test: generate ## run tests
@mkdir -p coverage
Expand All @@ -49,7 +54,10 @@ install-courtney: ## Install courtney for code coverage
@(cd courtney && go get ./... && go build courtney.go)
@go get ./...

install-deps: | install-gofumpt install-courtney install-mockgen ## Install some project dependencies
install-abigen: ## install abigen
go install github.com/ethereum/go-ethereum/cmd/abigen@latest

install-deps: | install-gofumpt install-courtney install-mockgen install-abigen ## Install some project dependencies

coverage: ## show tests coverage
@go tool cover -html=coverage/coverage.out -o coverage/coverage.html
Expand Down
1 change: 0 additions & 1 deletion configs/public_rpcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ var networkRPCs = map[string]RPC{
NetworkHolesky: {
NetworkName: NetworkHolesky,
PublicRPCs: []string{
"https://holesky.drpc.org",
"https://ethereum-holesky-rpc.publicnode.com",
"https://endpoints.omniatech.io/v1/eth/holesky/public",
"https://ethereum-holesky.blockpi.network/v1/rpc/public",
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/quickstart/install-guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Changes made to a profile file may not apply until the next time you log into yo

If you want to install Sedge on a Linux machine, we recommend installing some meta-packages to make the build process possible. You can install them with the following command in some of the major platforms:

Ubuntu and Debian based: `sudo apt-get install gcc g++ build-essential`
Ubuntu and Debian based: `sudo apt-get install gcc g++ abigen build-essential`

Arch: `sudo pacman -S base-devel`

Expand Down
52 changes: 52 additions & 0 deletions internal/lido/contracts/contract_setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright 2022 Nethermind
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package contracts

import (
"fmt"

"github.com/NethermindEth/sedge/configs"
"github.com/ethereum/go-ethereum/ethclient"
)

func connectToRPCETH(RPCs []string) (*ethclient.Client, error) {
var client *ethclient.Client
var err error

for _, url := range RPCs {
client, err = ethclient.Dial(url)
if err == nil {
return client, nil
}
}

return nil, fmt.Errorf("failed to connect to any RPC URL")
}

func ConnectClient(network string) (*ethclient.Client, error) {
rpcs, err := configs.GetPublicRPCs(network)
if err != nil {
return nil, fmt.Errorf("failed to get public RPC: %w", err)
}

// Connect to the RPC endpoint
client, err := connectToRPCETH(rpcs)
if err != nil {
return nil, fmt.Errorf("failed to connect to RPC: %w", err)
}

return client, nil
}
46 changes: 46 additions & 0 deletions internal/lido/contracts/contractsAddress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
Copyright 2022 Nethermind
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package contracts

import "github.com/NethermindEth/sedge/configs"

const (
// Contract names
CSModule = "csmodule"
CSAccounting = "sepolia"
CSFeeDistributor = "gnosis"
MEVBoostRelayAllowedList = "mevboostrelayallowedlist"
)

var deployedAddresses = map[string]map[string]string{
CSModule: {
configs.NetworkHolesky: "0x4562c3e63c2e586cD1651B958C22F88135aCAd4f",
},
CSAccounting: {
configs.NetworkHolesky: "0xc093e53e8F4b55A223c18A2Da6fA00e60DD5EFE1",
},
CSFeeDistributor: {
configs.NetworkHolesky: "0xD7ba648C8F72669C6aE649648B516ec03D07c8ED",
},
MEVBoostRelayAllowedList: {
configs.NetworkMainnet: "0xF95f069F9AD107938F6ba802a3da87892298610E",
configs.NetworkHolesky: "0x2d86C5855581194a386941806E38cA119E50aEA3",
},
}

func DeployedAddresses(contractName string) map[string]string {
return deployedAddresses[contractName]
}
1 change: 1 addition & 0 deletions internal/lido/contracts/csaccounting/CSAccounting.abi

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions internal/lido/contracts/csaccounting/CSAccounting.bin

Large diffs are not rendered by default.

96 changes: 96 additions & 0 deletions internal/lido/contracts/csaccounting/bonds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
Copyright 2022 Nethermind
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package csaccounting

import (
"fmt"
"math/big"

"github.com/NethermindEth/sedge/internal/lido/contracts"
"github.com/ethereum/go-ethereum/common"
)

// BondInfo : Struct represent bond info of Node Operator
type BondInfo struct {
Current *big.Int
Required *big.Int
Excess *big.Int
Missed *big.Int
}

/*
BondSummary :
This function is responsible for:
retrieving bond info for Lido CSM node
params :-
network (string): The name of the network (e.g."holesky").
nodeID (*big.Int): Node Operator ID
returns :-
a. BondInfo
Struct that include bond info
b. error
Error if any
*/
func BondSummary(network string, nodeID *big.Int) (BondInfo, error) {
var bondsInfo BondInfo
if nodeID.Sign() < 0 {
return bondsInfo, fmt.Errorf("node ID value out-of-bounds: can't be negative")
}

contract, err := csAccountingContract(network)
if err != nil {
return bondsInfo, fmt.Errorf("failed to call csAccountingContract: %w", err)
}

result, err := contract.GetBondSummary(nil, nodeID)
if err != nil {
return bondsInfo, fmt.Errorf("failed to call GetBondSummary: %w", err)
}
bondsInfo.Current = result.Current
bondsInfo.Required = result.Required

// Calculate excess and missed bond amounts
excess := new(big.Int).Sub(bondsInfo.Current, bondsInfo.Required)
missed := new(big.Int).Sub(bondsInfo.Required, bondsInfo.Current)

// Set to zero if negative
if excess.Sign() < 0 {
excess.SetInt64(0)
}
if missed.Sign() < 0 {
missed.SetInt64(0)
}

bondsInfo.Excess = excess
bondsInfo.Missed = missed
return bondsInfo, nil
}

func csAccountingContract(network string) (*Csaccounting, error) {
client, err := contracts.ConnectClient(network)
if err != nil {
return nil, fmt.Errorf("failed to connect to client: %w", err)
}
defer client.Close()

contractName := contracts.CSAccounting
address := common.HexToAddress(contracts.DeployedAddresses(contractName)[network])
contract, err := NewCsaccounting(address, client)
if err != nil {
return nil, fmt.Errorf("failed to create CSAccounting instance: %w", err)
}
return contract, nil
}
73 changes: 73 additions & 0 deletions internal/lido/contracts/csaccounting/bonds_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
Copyright 2022 Nethermind
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package csaccounting

import (
"io"
"log"
"math/big"
"testing"
)

func TestBondSummary(t *testing.T) {
log.SetOutput(io.Discard)
tcs := []struct {
name string
network string
nodeID *big.Int
invalidID bool
}{
{
"BondSummary with valid ID, Holesky #1", "holesky", big.NewInt(2), false,
},
{
"BondSummary with valid ID, Holesky #2", "holesky", big.NewInt(14), false,
},
{
"BondSummary with invalid ID, Holesky ", "holesky", big.NewInt(-6), true,
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
var expectedExcess, expectedMissed *big.Int
bond, err := BondSummary(tc.network, tc.nodeID)
if err != nil && !tc.invalidID {
t.Fatalf("failed to call BondsSummary: %v", err)
} else if err != nil && tc.invalidID {
t.Skipf("Expected error: %v", err)
}

// if current amount is greater than required
if bond.Current.Cmp(bond.Required) == 1 {
expectedExcess = new(big.Int).Sub(bond.Current, bond.Required)
expectedMissed = big.NewInt(0)
} else if bond.Current.Cmp(bond.Required) == -1 {
expectedExcess = big.NewInt(0)
expectedMissed = new(big.Int).Sub(bond.Required, bond.Current)
} else {
expectedExcess = big.NewInt(0)
expectedMissed = big.NewInt(0)
}

if bond.Excess.Cmp(expectedExcess) != 0 {
t.Errorf("not same excess bond amount, expected %v, got: %v", expectedExcess, bond.Excess)
}
if bond.Missed.Cmp(expectedMissed) != 0 {
t.Errorf("not same missed bond amount, expected %v, got: %v", expectedMissed, bond.Missed)
}
})
}
}
Loading

0 comments on commit 01fcb11

Please sign in to comment.