Skip to content

Commit d4eb749

Browse files
committed
feat: integrate address directory to eth reader
- Add NewReaderWithAddressDirectory() for address directory-based initialization - ContractNames constants matching AddressDirectoryConstants.sol - optional AddressDirectoryFlag, BlsOperatorStateRetrieverFlag, and EigenDAServiceManagerFlag - validation to require either address directory OR both legacy flags - backward compatibility for existing deployments without address directory
1 parent 6531878 commit d4eb749

File tree

48 files changed

+1682
-112
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1682
-112
lines changed

api/clients/v2/examples/client_construction.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ import (
2828
// These constants are specific to the EigenDA holesky testnet. To execute the provided examples on a different
2929
// network, you will need to set these constants to the correct values, based on the chosen network.
3030
const (
31-
ethRPCURL = "https://ethereum-holesky-rpc.publicnode.com"
32-
disperserHostname = "disperser-testnet-holesky.eigenda.xyz"
33-
certVerifierRouterAddress = "0x7F40A8e1B62aa1c8Afed23f6E8bAe0D340A4BC4e"
34-
registryCoordinatorAddress = "0x53012C69A189cfA2D9d29eb6F19B32e0A2EA3490"
31+
ethRPCURL = "https://ethereum-holesky-rpc.publicnode.com"
32+
disperserHostname = "disperser-testnet-holesky.eigenda.xyz"
33+
certVerifierRouterAddress = "0x7F40A8e1B62aa1c8Afed23f6E8bAe0D340A4BC4e"
34+
registryCoordinatorAddress = "0x53012C69A189cfA2D9d29eb6F19B32e0A2EA3490"
35+
addressDirectoryAddress = "0x0000000000000000000000000000000000000000" // TODO: Replace with actual EigenDADirectory address when deployed
36+
// Legacy addresses (use addressDirectoryAddress instead when available)
3537
blsOperatorStateRetrieverAddress = "0x003497Dd77E5B73C40e8aCbB562C8bb0410320E7"
3638
eigenDAServiceManagerAddress = "0xD4A7E1Bd8015057293f0D0A557088c286942e84b"
3739
)
@@ -329,14 +331,24 @@ func createKzgConfig() kzg.KzgConfig {
329331
}
330332

331333
func createEthReader(logger logging.Logger, ethClient common.EthClient) (*eth.Reader, error) {
334+
// Prefer address directory when available
335+
if addressDirectoryAddress != "0x0000000000000000000000000000000000000000" {
336+
ethReader, err := eth.NewReaderWithAddressDirectory(logger, ethClient, addressDirectoryAddress)
337+
if err != nil {
338+
return nil, fmt.Errorf("new reader with address directory: %w", err)
339+
}
340+
return ethReader, nil
341+
}
342+
343+
// Fallback to legacy approach
332344
ethReader, err := eth.NewReader(
333345
logger,
334346
ethClient,
335347
blsOperatorStateRetrieverAddress,
336348
eigenDAServiceManagerAddress,
337349
)
338350
if err != nil {
339-
return nil, fmt.Errorf("new reader: %w", err)
351+
return nil, fmt.Errorf("new reader legacy: %w", err)
340352
}
341353

342354
return ethReader, nil

contracts/bindings/EigenDADirectory/binding.go

Lines changed: 1149 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/compile.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ contracts="PaymentVault \
4949
EigenDAThresholdRegistry \
5050
EigenDARelayRegistry \
5151
IEigenDARelayRegistry \
52-
EigenDADisperserRegistry"
52+
EigenDADisperserRegistry \
53+
EigenDADirectory"
5354

5455
for contract in $contracts; do
5556
create_binding_abi_only ./ $contract ./bindings

contracts/script/SetUpEigenDA.s.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ contract SetupEigenDA is EigenDADeployer, EigenLayerUtils {
189189
}
190190

191191
string memory output = "eigenDA deployment output";
192+
vm.serializeAddress(output, "eigenDADirectory", address(eigenDADirectory));
192193
vm.serializeAddress(output, "eigenDAServiceManager", address(eigenDAServiceManager));
193194
vm.serializeAddress(output, "operatorStateRetriever", address(operatorStateRetriever));
194195
vm.serializeAddress(output, "blsApkRegistry", address(apkRegistry));

core/eth/reader.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ import (
88
"math/big"
99
"strings"
1010

11+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
12+
"github.com/ethereum/go-ethereum/crypto"
13+
1114
"github.com/Layr-Labs/eigenda/common"
1215
avsdir "github.com/Layr-Labs/eigenda/contracts/bindings/AVSDirectory"
1316
blsapkreg "github.com/Layr-Labs/eigenda/contracts/bindings/BLSApkRegistry"
1417
delegationmgr "github.com/Layr-Labs/eigenda/contracts/bindings/DelegationManager"
18+
eigendadirectory "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDADirectory"
1519
disperserreg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDADisperserRegistry"
1620
relayreg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDARelayRegistry"
1721
eigendasrvmg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAServiceManager"
@@ -25,10 +29,8 @@ import (
2529
stakereg "github.com/Layr-Labs/eigenda/contracts/bindings/StakeRegistry"
2630
"github.com/Layr-Labs/eigenda/core"
2731
"github.com/Layr-Labs/eigensdk-go/logging"
28-
"github.com/ethereum/go-ethereum/accounts/abi/bind"
2932
gethcommon "github.com/ethereum/go-ethereum/common"
3033
"github.com/ethereum/go-ethereum/core/types"
31-
"github.com/ethereum/go-ethereum/crypto"
3234
"github.com/pingcap/errors"
3335

3436
blssigner "github.com/Layr-Labs/eigensdk-go/signer/bls"
@@ -52,6 +54,7 @@ type ContractBindings struct {
5254
RelayRegistry *relayreg.ContractEigenDARelayRegistry
5355
ThresholdRegistry *thresholdreg.ContractEigenDAThresholdRegistry
5456
DisperserRegistry *disperserreg.ContractEigenDADisperserRegistry
57+
AddressDirectory *eigendadirectory.ContractEigenDADirectory
5558
}
5659

5760
type Reader struct {
@@ -80,6 +83,44 @@ func NewReader(
8083
return e, err
8184
}
8285

86+
// NewReaderWithAddressDirectory creates a new Reader using an address directory contract address
87+
func NewReaderWithAddressDirectory(
88+
logger logging.Logger,
89+
client common.EthClient,
90+
addressDirectoryHexAddr string) (*Reader, error) {
91+
92+
e := &Reader{
93+
ethClient: client,
94+
logger: logger.With("component", "Reader"),
95+
}
96+
97+
addressDirectoryAddr := gethcommon.HexToAddress(addressDirectoryHexAddr)
98+
addressDirectory, err := eigendadirectory.NewContractEigenDADirectory(addressDirectoryAddr, client)
99+
if err != nil {
100+
return nil, fmt.Errorf("failed to fetch EigenDADirectory contract: %w", err)
101+
}
102+
103+
// Convert contract names to keccak256 hashes as expected by the contract
104+
operatorStateRetrieverKey := crypto.Keccak256Hash([]byte(ContractNames.OperatorStateRetriever))
105+
blsOperatorStateRetrieverAddr, err := addressDirectory.GetAddress(&bind.CallOpts{}, operatorStateRetrieverKey)
106+
if err != nil {
107+
return nil, fmt.Errorf("failed to get operator state retriever address: %w", err)
108+
}
109+
110+
serviceManagerKey := crypto.Keccak256Hash([]byte(ContractNames.ServiceManager))
111+
eigenDAServiceManagerAddr, err := addressDirectory.GetAddress(&bind.CallOpts{}, serviceManagerKey)
112+
if err != nil {
113+
return nil, fmt.Errorf("failed to get service manager address: %w", err)
114+
}
115+
err = e.updateContractBindings(blsOperatorStateRetrieverAddr, eigenDAServiceManagerAddr)
116+
if err != nil {
117+
return nil, fmt.Errorf("failed to update contract bindings: %w", err)
118+
}
119+
return e, nil
120+
}
121+
122+
// updateContractBindings updates the contract bindings for the reader
123+
// TODO: move to use address directory contract once all contracts are written into the directory
83124
func (t *Reader) updateContractBindings(blsOperatorStateRetrieverAddr, eigenDAServiceManagerAddr gethcommon.Address) error {
84125

85126
contractEigenDAServiceManager, err := eigendasrvmg.NewContractEigenDAServiceManager(eigenDAServiceManagerAddr, t.ethClient)

core/eth/utils.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package eth
22

33
import (
4+
"fmt"
45
"math/big"
56
"slices"
67

@@ -10,6 +11,7 @@ import (
1011
eigendasrvmg "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAServiceManager"
1112
paymentvault "github.com/Layr-Labs/eigenda/contracts/bindings/PaymentVault"
1213

14+
gethcommon "github.com/ethereum/go-ethereum/common"
1315
"github.com/ethereum/go-ethereum/crypto"
1416
)
1517

@@ -176,3 +178,56 @@ func GetAllQuorumIDs(quorumCount uint8) []core.QuorumID {
176178
}
177179
return quorumIDs
178180
}
181+
182+
// ContractNames defines the standard contract names used in the address directory
183+
// TODO: consider auto-generating this from the address directory contract
184+
// These values must match exactly the constants defined in AddressDirectoryConstants.sol.
185+
var ContractNames = struct {
186+
ServiceManager string
187+
OperatorStateRetriever string
188+
RegistryCoordinator string
189+
BLSApkRegistry string
190+
IndexRegistry string
191+
StakeRegistry string
192+
SocketRegistry string
193+
PaymentVault string
194+
EjectionManager string
195+
RelayRegistry string
196+
ThresholdRegistry string
197+
DisperserRegistry string
198+
}{
199+
ServiceManager: "SERVICE_MANAGER",
200+
OperatorStateRetriever: "OPERATOR_STATE_RETRIEVER",
201+
RegistryCoordinator: "REGISTRY_COORDINATOR",
202+
BLSApkRegistry: "BLS_APK_REGISTRY",
203+
IndexRegistry: "INDEX_REGISTRY",
204+
StakeRegistry: "STAKE_REGISTRY",
205+
SocketRegistry: "SOCKET_REGISTRY",
206+
PaymentVault: "PAYMENT_VAULT",
207+
EjectionManager: "EJECTION_MANAGER",
208+
RelayRegistry: "RELAY_REGISTRY",
209+
ThresholdRegistry: "THRESHOLD_REGISTRY",
210+
DisperserRegistry: "DISPERSER_REGISTRY",
211+
}
212+
213+
// ValidateAddressConfig validates that either address directory is provided OR both individual addresses are provided
214+
// and that all provided addresses are valid hex addresses.
215+
func ValidateAddressConfig(addressDirectory, blsOperatorStateRetriever, eigenDAServiceManager string) error {
216+
// Validate that either address directory is provided OR both individual addresses are provided
217+
if addressDirectory == "" && (blsOperatorStateRetriever == "" || eigenDAServiceManager == "") {
218+
return fmt.Errorf("either address-directory must be provided, or both bls-operator-state-retriever and eigenda-service-manager addresses must be provided")
219+
}
220+
221+
// Validate address formats
222+
if addressDirectory != "" && !gethcommon.IsHexAddress(addressDirectory) {
223+
return fmt.Errorf("address-directory must be a valid hex address")
224+
}
225+
if blsOperatorStateRetriever != "" && !gethcommon.IsHexAddress(blsOperatorStateRetriever) {
226+
return fmt.Errorf("bls-operator-state-retriever must be a valid hex address")
227+
}
228+
if eigenDAServiceManager != "" && !gethcommon.IsHexAddress(eigenDAServiceManager) {
229+
return fmt.Errorf("eigenda-service-manager must be a valid hex address")
230+
}
231+
232+
return nil
233+
}

core/eth/writer.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type Writer struct {
3434

3535
var _ core.Writer = (*Writer)(nil)
3636

37+
// NewWriter creates a new Writer using individual contract addresses (deprecated, use NewWriter instead)
3738
func NewWriter(
3839
logger logging.Logger,
3940
client common.EthClient,
@@ -58,6 +59,26 @@ func NewWriter(
5859
return e, err
5960
}
6061

62+
// NewWriterWithAddressDirectory creates a new Writer using an address directory contract address
63+
func NewWriterWithAddressDirectory(
64+
logger logging.Logger,
65+
client common.EthClient,
66+
addressDirectoryHexAddr string) (*Writer, error) {
67+
68+
r, err := NewReaderWithAddressDirectory(logger, client, addressDirectoryHexAddr)
69+
if err != nil {
70+
return nil, fmt.Errorf("failed to create reader with address directory: %w", err)
71+
}
72+
73+
e := &Writer{
74+
ethClient: client,
75+
logger: logger.With("component", "Writer"),
76+
Reader: r,
77+
}
78+
79+
return e, nil
80+
}
81+
6182
// RegisterOperator registers a new operator with the given public key and socket with the provided quorum ids.
6283
// If the operator is already registered with a given quorum id, the transaction will fail (noop) and an error
6384
// will be returned.

disperser/cmd/apiserver/flags/flags.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,22 @@ var (
4646
EnvVar: common.PrefixEnvVar(envVarPrefix, "GRPC_STREAM_TIMEOUT"),
4747
Value: time.Second * 10,
4848
}
49+
AddressDirectoryFlag = cli.StringFlag{
50+
Name: common.PrefixFlag(FlagPrefix, "address-directory"),
51+
Usage: "Address of the EigenDA Directory contract (preferred over individual contract addresses)",
52+
Required: false,
53+
EnvVar: common.PrefixEnvVar(envVarPrefix, "ADDRESS_DIRECTORY"),
54+
}
4955
BlsOperatorStateRetrieverFlag = cli.StringFlag{
5056
Name: common.PrefixFlag(FlagPrefix, "bls-operator-state-retriever"),
5157
Usage: "Address of the BLS Operator State Retriever",
52-
Required: true,
53-
EnvVar: common.PrefixEnvVar(envVarPrefix, "BLS_OPERATOR_STATE_RETRIVER"),
58+
Required: false,
59+
EnvVar: common.PrefixEnvVar(envVarPrefix, "BLS_OPERATOR_STATE_RETRIEVER"),
5460
}
5561
EigenDAServiceManagerFlag = cli.StringFlag{
5662
Name: common.PrefixFlag(FlagPrefix, "eigenda-service-manager"),
5763
Usage: "Address of the EigenDA Service Manager",
58-
Required: true,
64+
Required: false,
5965
EnvVar: common.PrefixEnvVar(envVarPrefix, "EIGENDA_SERVICE_MANAGER"),
6066
}
6167
/* Optional Flags*/
@@ -270,8 +276,6 @@ var requiredFlags = []cli.Flag{
270276
DynamoDBTableNameFlag,
271277
GrpcPortFlag,
272278
BucketTableName,
273-
BlsOperatorStateRetrieverFlag,
274-
EigenDAServiceManagerFlag,
275279
}
276280

277281
var optionalFlags = []cli.Flag{
@@ -295,6 +299,9 @@ var optionalFlags = []cli.Flag{
295299
NtpServerFlag,
296300
NtpSyncIntervalFlag,
297301
ReservedOnly,
302+
AddressDirectoryFlag,
303+
BlsOperatorStateRetrieverFlag,
304+
EigenDAServiceManagerFlag,
298305
}
299306

300307
// Flags contains the list of configuration options available to the binary.

disperser/cmd/apiserver/lib/apiserver.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ func RunDisperserServer(ctx *cli.Context) error {
5252
return err
5353
}
5454

55-
transactor, err := eth.NewReader(logger, client, config.BLSOperatorStateRetrieverAddr, config.EigenDAServiceManagerAddr)
55+
var transactor *eth.Reader
56+
if config.AddressDirectoryAddr != "" {
57+
transactor, err = eth.NewReaderWithAddressDirectory(logger, client, config.AddressDirectoryAddr)
58+
} else {
59+
transactor, err = eth.NewReader(logger, client, config.BLSOperatorStateRetrieverAddr, config.EigenDAServiceManagerAddr)
60+
}
5661
if err != nil {
5762
return err
5863
}

disperser/cmd/apiserver/lib/config.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/Layr-Labs/eigenda/disperser/cmd/apiserver/flags"
1414
"github.com/Layr-Labs/eigenda/disperser/common/blobstore"
1515
"github.com/Layr-Labs/eigenda/encoding/kzg"
16+
gethcommon "github.com/ethereum/go-ethereum/common"
1617
"github.com/urfave/cli"
1718
)
1819

@@ -47,6 +48,7 @@ type Config struct {
4748
MaxNumSymbolsPerBlob uint
4849
OnchainStateRefreshInterval time.Duration
4950

51+
AddressDirectoryAddr string
5052
BLSOperatorStateRetrieverAddr string
5153
EigenDAServiceManagerAddr string
5254
AuthPmtStateRequestMaxPastAge time.Duration
@@ -96,6 +98,26 @@ func NewConfig(ctx *cli.Context) (Config, error) {
9698
}
9799
}
98100

101+
// Validate that either address directory is provided OR both individual addresses are provided
102+
addressDirectoryAddr := ctx.GlobalString(flags.AddressDirectoryFlag.Name)
103+
blsOperatorStateRetrieverAddr := ctx.GlobalString(flags.BlsOperatorStateRetrieverFlag.Name)
104+
eigenDAServiceManagerAddr := ctx.GlobalString(flags.EigenDAServiceManagerFlag.Name)
105+
106+
if addressDirectoryAddr == "" && (blsOperatorStateRetrieverAddr == "" || eigenDAServiceManagerAddr == "") {
107+
return Config{}, fmt.Errorf("either address-directory must be provided, or both bls-operator-state-retriever and eigenda-service-manager addresses must be provided")
108+
}
109+
110+
// Validate address formats
111+
if addressDirectoryAddr != "" && !gethcommon.IsHexAddress(addressDirectoryAddr) {
112+
return Config{}, fmt.Errorf("address-directory must be a valid hex address")
113+
}
114+
if blsOperatorStateRetrieverAddr != "" && !gethcommon.IsHexAddress(blsOperatorStateRetrieverAddr) {
115+
return Config{}, fmt.Errorf("bls-operator-state-retriever must be a valid hex address")
116+
}
117+
if eigenDAServiceManagerAddr != "" && !gethcommon.IsHexAddress(eigenDAServiceManagerAddr) {
118+
return Config{}, fmt.Errorf("eigenda-service-manager must be a valid hex address")
119+
}
120+
99121
config := Config{
100122
DisperserVersion: DisperserVersion(version),
101123
AwsClientConfig: aws.ReadClientConfig(ctx, flags.FlagPrefix),
@@ -131,8 +153,9 @@ func NewConfig(ctx *cli.Context) (Config, error) {
131153
MaxNumSymbolsPerBlob: ctx.GlobalUint(flags.MaxNumSymbolsPerBlob.Name),
132154
OnchainStateRefreshInterval: ctx.GlobalDuration(flags.OnchainStateRefreshInterval.Name),
133155

134-
BLSOperatorStateRetrieverAddr: ctx.GlobalString(flags.BlsOperatorStateRetrieverFlag.Name),
135-
EigenDAServiceManagerAddr: ctx.GlobalString(flags.EigenDAServiceManagerFlag.Name),
156+
AddressDirectoryAddr: addressDirectoryAddr,
157+
BLSOperatorStateRetrieverAddr: blsOperatorStateRetrieverAddr,
158+
EigenDAServiceManagerAddr: eigenDAServiceManagerAddr,
136159
AuthPmtStateRequestMaxPastAge: ctx.GlobalDuration(flags.AuthPmtStateRequestMaxPastAge.Name),
137160
AuthPmtStateRequestMaxFutureAge: ctx.GlobalDuration(flags.AuthPmtStateRequestMaxFutureAge.Name),
138161
NtpServer: ctx.GlobalString(flags.NtpServerFlag.Name),

0 commit comments

Comments
 (0)