Skip to content

Commit

Permalink
more robust client builder: panic instead of NPE if Network is nil, f…
Browse files Browse the repository at this point in the history
…ind network by name instead of modifying the first one
  • Loading branch information
Tofel committed Sep 6, 2024
1 parent adb32bf commit 851c9f6
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 25 deletions.
3 changes: 3 additions & 0 deletions seth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,9 @@ func (m *Client) TransferETHFromKey(ctx context.Context, fromKeyNum int, to stri

// WaitMined the same as bind.WaitMined, awaits transaction receipt until timeout
func (m *Client) WaitMined(ctx context.Context, l zerolog.Logger, b bind.DeployBackend, tx *types.Transaction) (*types.Receipt, error) {
l.Info().
Str("TX", tx.Hash().String()).
Msg("Waiting for transaction to be mined")
queryTicker := time.NewTicker(time.Second)
defer queryTicker.Stop()
ctx, cancel := context.WithTimeout(ctx, m.Cfg.Network.TxnTimeout.Duration())
Expand Down
66 changes: 41 additions & 25 deletions seth/client_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,38 +47,41 @@ func NewClientBuilder() *ClientBuilder {
// WithRpcUrl sets the RPC URL for the config.
// Default value is an empty string (which is an incorrect value).
func (c *ClientBuilder) WithRpcUrl(url string) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.URLs = []string{url}
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].URLs = []string{url}
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.URLs = []string{url}
}
return c
}

// WithPrivateKeys sets the private keys for the config. At least one is required to build a valid config.
// Default value is an empty slice (which is an incorrect value).
func (c *ClientBuilder) WithPrivateKeys(pks []string) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.PrivateKeys = pks
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].PrivateKeys = pks
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.PrivateKeys = pks
}
return c
}

// WithNetworkName sets the network name, useful mostly for debugging and logging.
// Default value is "default".
func (c *ClientBuilder) WithNetworkName(name string) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.Name = name
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].Name = name
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.Name = name
}
return c
}
Expand All @@ -89,70 +92,75 @@ func (c *ClientBuilder) WithNetworkName(name string) *ClientBuilder {
// Following priorities are supported: "slow", "standard" and "fast"
// Default values are true for enabled, 200 blocks for estimation and "standard" for priority.
func (c *ClientBuilder) WithGasPriceEstimations(enabled bool, estimationBlocks uint64, txPriority string) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.GasPriceEstimationEnabled = enabled
c.config.Network.GasPriceEstimationBlocks = estimationBlocks
c.config.Network.GasPriceEstimationTxPriority = txPriority
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].GasPriceEstimationEnabled = enabled
c.config.Networks[0].GasPriceEstimationBlocks = estimationBlocks
c.config.Networks[0].GasPriceEstimationTxPriority = txPriority
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.GasPriceEstimationEnabled = enabled
net.GasPriceEstimationBlocks = estimationBlocks
net.GasPriceEstimationTxPriority = txPriority
}
return c
}

// WithEIP1559DynamicFees enables or disables EIP-1559 dynamic fees. If enabled, you should set gas fee cap and gas tip cap with `WithDynamicGasPrices()`
// Default value is true.
func (c *ClientBuilder) WithEIP1559DynamicFees(enabled bool) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.EIP1559DynamicFees = enabled
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].EIP1559DynamicFees = enabled
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.EIP1559DynamicFees = enabled
}
return c
}

// WithLegacyGasPrice sets the gas price for legacy transactions that will be used only if EIP-1559 dynamic fees are disabled.
// Default value is 1 gwei.
func (c *ClientBuilder) WithLegacyGasPrice(gasPrice int64) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.GasPrice = gasPrice
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].GasPrice = gasPrice
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.GasPrice = gasPrice
}
return c
}

// WithDynamicGasPrices sets the gas fee cap and gas tip cap for EIP-1559 dynamic fees. These values will be used only if EIP-1559 dynamic fees are enabled.
// Default values are 150 gwei for gas fee cap and 50 gwei for gas tip cap.
func (c *ClientBuilder) WithDynamicGasPrices(gasFeeCap, gasTipCap int64) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.GasFeeCap = gasFeeCap
c.config.Network.GasTipCap = gasTipCap
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].GasFeeCap = gasFeeCap
c.config.Networks[0].GasTipCap = gasTipCap
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.GasFeeCap = gasFeeCap
net.GasTipCap = gasTipCap
}
return c
}

// WithTransferGasFee sets the gas fee for transfer transactions. This value is used, when sending funds to ephemeral keys or returning funds to root private key.
// Default value is 21_000 wei.
func (c *ClientBuilder) WithTransferGasFee(gasFee int64) *ClientBuilder {
c.config.Network.TransferGasFee = gasFee
func (c *ClientBuilder) WithTransferGasFee(transferGasFee int64) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.TransferGasFee = transferGasFee
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].TransferGasFee = gasFee
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.TransferGasFee = transferGasFee
}
return c
}
Expand All @@ -172,25 +180,27 @@ func (c *ClientBuilder) WithGasBumping(retries uint, maxGasPrice int64, customBu
// WithTransactionTimeout sets the timeout for transactions. If the transaction is not mined within this time, it will be considered failed.
// Default value is 5 minutes.
func (c *ClientBuilder) WithTransactionTimeout(timeout time.Duration) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.TxnTimeout = MustMakeDuration(timeout)
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].TxnTimeout = MustMakeDuration(timeout)
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.TxnTimeout = MustMakeDuration(timeout)
}
return c
}

// WithRpcDialTimeout sets the timeout for dialing the RPC server. If the connection is not established within this time, it will be considered failed.
// Default value is 1 minute.
func (c *ClientBuilder) WithRpcDialTimeout(timeout time.Duration) *ClientBuilder {
c.assertNetworkIsSet()
c.config.Network.DialTimeout = MustMakeDuration(timeout)
// defensive programming
if len(c.config.Networks) == 0 {
c.config.Networks = append(c.config.Networks, c.config.Network)
} else {
c.config.Networks[0].DialTimeout = MustMakeDuration(timeout)
} else if net := c.config.findNetworkByName(c.config.Network.Name); net != nil {
net.DialTimeout = MustMakeDuration(timeout)
}
return c
}
Expand Down Expand Up @@ -252,3 +262,9 @@ func (c *ClientBuilder) WithNonceManager(rateLimitSec int, retries uint, timeout
func (c *ClientBuilder) Build() (*Client, error) {
return NewClientWithConfig(c.config)
}

func (c *ClientBuilder) assertNetworkIsSet() {
if c.config.Network == nil {
panic("Network is required to use this method, but it was nil")
}
}
10 changes: 10 additions & 0 deletions seth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,13 @@ func (c *Config) hasOutput(output string) bool {

return false
}

func (c *Config) findNetworkByName(name string) *Network {
for _, n := range c.Networks {
if strings.EqualFold(n.Name, name) {
return n
}
}

return nil
}

0 comments on commit 851c9f6

Please sign in to comment.