Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions constants/resolve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package constants

import (
"context"
"fmt"
"strings"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)

const fwssABI = `[
{"type":"function","name":"paymentsContractAddress","inputs":[],"outputs":[{"name":"","type":"address"}],"stateMutability":"view"},
{"type":"function","name":"viewContractAddress","inputs":[],"outputs":[{"name":"","type":"address"}],"stateMutability":"view"},
{"type":"function","name":"pdpVerifierAddress","inputs":[],"outputs":[{"name":"","type":"address"}],"stateMutability":"view"},
{"type":"function","name":"serviceProviderRegistry","inputs":[],"outputs":[{"name":"","type":"address"}],"stateMutability":"view"},
{"type":"function","name":"sessionKeyRegistry","inputs":[],"outputs":[{"name":"","type":"address"}],"stateMutability":"view"}
]`

// NetworkAddresses holds the full set of addresses derived from an FWSS contract.
type NetworkAddresses struct {
FWSS common.Address
Payments common.Address
StateView common.Address
PDPVerifier common.Address
SPRegistry common.Address
SessionKeyRegistry common.Address
}

// ResolveFromFWSS queries a FWSS contract to derive all dependent addresses.
// This is the runtime equivalent of what `go generate` does at build time
// for mainnet and calibration.
func ResolveFromFWSS(ctx context.Context, client *ethclient.Client, fwssAddr common.Address) (*NetworkAddresses, error) {
parsed, err := abi.JSON(strings.NewReader(fwssABI))
if err != nil {
return nil, fmt.Errorf("parse FWSS abi: %w", err)
}

callView := func(method string) (common.Address, error) {
data, err := parsed.Pack(method)
if err != nil {
return common.Address{}, fmt.Errorf("pack %s: %w", method, err)
}
result, err := client.CallContract(ctx, ethereum.CallMsg{
To: &fwssAddr,
Data: data,
}, nil)
if err != nil {
return common.Address{}, fmt.Errorf("call %s: %w", method, err)
}
var addr common.Address
if err := parsed.UnpackIntoInterface(&addr, method, result); err != nil {
return common.Address{}, fmt.Errorf("unpack %s: %w", method, err)
}
return addr, nil
}

addrs := &NetworkAddresses{FWSS: fwssAddr}

addrs.Payments, err = callView("paymentsContractAddress")
if err != nil {
return nil, err
}
addrs.StateView, err = callView("viewContractAddress")
if err != nil {
return nil, err
}
addrs.PDPVerifier, err = callView("pdpVerifierAddress")
if err != nil {
return nil, err
}
addrs.SPRegistry, err = callView("serviceProviderRegistry")
if err != nil {
return nil, err
}
addrs.SessionKeyRegistry, err = callView("sessionKeyRegistry")
if err != nil {
return nil, err
}

return addrs, nil
}

// RegisterNetwork populates the package-level address maps for a network.
// Use this for devnet or custom deployments where addresses are resolved
// at runtime from FWSS rather than baked in at build time.
func RegisterNetwork(network Network, addrs *NetworkAddresses) {
WarmStorageAddresses[network] = addrs.FWSS
PaymentsAddresses[network] = addrs.Payments
WarmStorageStateViewAddresses[network] = addrs.StateView
PDPVerifierAddresses[network] = addrs.PDPVerifier
SPRegistryAddresses[network] = addrs.SPRegistry
SessionKeyRegistryAddresses[network] = addrs.SessionKeyRegistry
}
41 changes: 1 addition & 40 deletions internal/generate/addresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,10 @@ func readAddresses(ctx context.Context, rpcURL string, fwssAddr common.Address)
type templateData struct {
Mainnet *networkAddresses
Calibration *networkAddresses
Devnet *networkAddresses
}

var tmpl = template.Must(template.New("addresses").Parse(`// Code generated by go generate; DO NOT EDIT.
// Source: FWSS contracts on mainnet, calibration{{ if .Devnet }}, and devnet{{ end }}
// Source: FWSS contracts on mainnet, calibration

package constants

Expand All @@ -123,60 +122,39 @@ import "github.com/ethereum/go-ethereum/common"
var (
FWSSAddressMainnet = common.HexToAddress("{{ .Mainnet.FWSS.Hex }}")
FWSSAddressCalibration = common.HexToAddress("{{ .Calibration.FWSS.Hex }}")
{{- if .Devnet }}
FWSSAddressDevnet = common.HexToAddress("{{ .Devnet.FWSS.Hex }}")
{{- end }}
)

// WarmStorageAddresses aliases the FWSS addresses (root of trust)
var WarmStorageAddresses = map[Network]common.Address{
NetworkMainnet: FWSSAddressMainnet,
NetworkCalibration: FWSSAddressCalibration,
{{- if .Devnet }}
NetworkDevnet: FWSSAddressDevnet,
{{- end }}
}

// derived addresses - read from FWSS contracts
var (
PaymentsAddresses = map[Network]common.Address{
NetworkMainnet: common.HexToAddress("{{ .Mainnet.Payments.Hex }}"),
NetworkCalibration: common.HexToAddress("{{ .Calibration.Payments.Hex }}"),
{{- if .Devnet }}
NetworkDevnet: common.HexToAddress("{{ .Devnet.Payments.Hex }}"),
{{- end }}
}

WarmStorageStateViewAddresses = map[Network]common.Address{
NetworkMainnet: common.HexToAddress("{{ .Mainnet.StateView.Hex }}"),
NetworkCalibration: common.HexToAddress("{{ .Calibration.StateView.Hex }}"),
{{- if .Devnet }}
NetworkDevnet: common.HexToAddress("{{ .Devnet.StateView.Hex }}"),
{{- end }}
}

PDPVerifierAddresses = map[Network]common.Address{
NetworkMainnet: common.HexToAddress("{{ .Mainnet.PDPVerifier.Hex }}"),
NetworkCalibration: common.HexToAddress("{{ .Calibration.PDPVerifier.Hex }}"),
{{- if .Devnet }}
NetworkDevnet: common.HexToAddress("{{ .Devnet.PDPVerifier.Hex }}"),
{{- end }}
}

SPRegistryAddresses = map[Network]common.Address{
NetworkMainnet: common.HexToAddress("{{ .Mainnet.SPRegistry.Hex }}"),
NetworkCalibration: common.HexToAddress("{{ .Calibration.SPRegistry.Hex }}"),
{{- if .Devnet }}
NetworkDevnet: common.HexToAddress("{{ .Devnet.SPRegistry.Hex }}"),
{{- end }}
}

SessionKeyRegistryAddresses = map[Network]common.Address{
NetworkMainnet: common.HexToAddress("{{ .Mainnet.SessionKeyRegistry.Hex }}"),
NetworkCalibration: common.HexToAddress("{{ .Calibration.SessionKeyRegistry.Hex }}"),
{{- if .Devnet }}
NetworkDevnet: common.HexToAddress("{{ .Devnet.SessionKeyRegistry.Hex }}"),
{{- end }}
}
)
`))
Expand Down Expand Up @@ -216,23 +194,6 @@ func main() {
Calibration: calibration,
}

// optionally read devnet addresses from a running foc-devnet instance.
// set DEVNET_RPC and DEVNET_FWSS to enable, e.g.:
// DEVNET_RPC=http://127.0.0.1:1234/rpc/v1 DEVNET_FWSS=0x4A8a... go generate ./constants/
devnetRPC := os.Getenv("DEVNET_RPC")
devnetFWSS := os.Getenv("DEVNET_FWSS")
if devnetRPC != "" && devnetFWSS != "" {
fwssAddr := common.HexToAddress(devnetFWSS)
fmt.Println("reading devnet addresses...")
devnet, err := readAddresses(ctx, devnetRPC, fwssAddr)
if err != nil {
fmt.Fprintf(os.Stderr, "devnet: %v\n", err)
os.Exit(1)
}
printAddresses("devnet", devnet)
data.Devnet = devnet
}

// go generate runs in the package's source directory
// if GOPACKAGE is set, we're running via go generate - output to current dir
// otherwise output to constants/ for manual invocation from repo root
Expand Down
14 changes: 14 additions & 0 deletions synapse.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ func New(ctx context.Context, opts Options) (*Client, error) {
warmStorageAddr = WarmStorageAddresses[network]
}

// for networks without static addresses (e.g. devnet), resolve from FWSS at runtime
if _, ok := constants.PDPVerifierAddresses[constants.Network(network)]; !ok {
if warmStorageAddr == (common.Address{}) {
ethClient.Close()
return nil, fmt.Errorf("network %s has no built-in addresses; set WarmStorageAddress (FWSS) to resolve at runtime", network)
}
addrs, err := constants.ResolveFromFWSS(ctx, ethClient, warmStorageAddr)
if err != nil {
ethClient.Close()
return nil, fmt.Errorf("failed to resolve addresses from FWSS on %s: %w", network, err)
}
constants.RegisterNetwork(constants.Network(network), addrs)
}

address := crypto.PubkeyToAddress(opts.PrivateKey.PublicKey)

client := &Client{
Expand Down
Loading