@@ -13,7 +13,6 @@ import (
1313 "github.com/ethereum/go-ethereum/crypto"
1414 "github.com/ethereum/go-ethereum/ethclient/simulated"
1515 "github.com/pelletier/go-toml/v2"
16- "github.com/pkg/errors"
1716)
1817
1918const (
@@ -131,16 +130,30 @@ func DefaultClient(rpcUrl string, privateKeys []string) (*Client, error) {
131130func ReadConfig () (* Config , error ) {
132131 cfgPath := os .Getenv (CONFIG_FILE_ENV_VAR )
133132 if cfgPath == "" {
134- return nil , errors .New (ErrEmptyConfigPath )
133+ return nil , fmt .Errorf ("SETH_CONFIG_PATH environment variable is not set. " +
134+ "Set it to the absolute path of your seth.toml configuration file.\n " +
135+ "Example: export SETH_CONFIG_PATH=/path/to/your/seth.toml" )
135136 }
136137 var cfg * Config
137138 d , err := os .ReadFile (cfgPath )
138139 if err != nil {
139- return nil , errors .Wrap (err , ErrReadSethConfig )
140+ return nil , fmt .Errorf ("failed to read Seth config file at '%s': %w\n " +
141+ "Ensure:\n " +
142+ " 1. The file exists at the specified path\n " +
143+ " 2. You have read permissions for the file\n " +
144+ " 3. The path is correct (set via SETH_CONFIG_PATH or parameter)" ,
145+ cfgPath , err )
140146 }
141147 err = toml .Unmarshal (d , & cfg )
142148 if err != nil {
143- return nil , errors .Wrap (err , ErrUnmarshalSethConfig )
149+ return nil , fmt .Errorf ("failed to parse Seth TOML config from '%s': %w\n " +
150+ "Ensure the file contains valid TOML syntax. " +
151+ "Common issues:\n " +
152+ " 1. Missing quotes around string values\n " +
153+ " 2. Invalid array or table syntax\n " +
154+ " 3. Duplicate keys\n " +
155+ "See example config: https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/seth/seth.toml" ,
156+ cfgPath , err )
144157 }
145158 absPath , err := filepath .Abs (cfgPath )
146159 if err != nil {
@@ -162,7 +175,15 @@ func ReadConfig() (*Config, error) {
162175 url := os .Getenv (URL_ENV_VAR )
163176
164177 if url == "" {
165- return nil , fmt .Errorf ("network not selected, set %s=... or %s=..., check TOML config for available networks" , NETWORK_ENV_VAR , URL_ENV_VAR )
178+ availableNetworks := make ([]string , 0 , len (cfg .Networks ))
179+ for _ , n := range cfg .Networks {
180+ availableNetworks = append (availableNetworks , n .Name )
181+ }
182+ return nil , fmt .Errorf ("network not selected. Set either:\n " +
183+ " - SETH_NETWORK to one of: %s\n " +
184+ " - SETH_URL to a custom RPC endpoint\n " +
185+ "Check your TOML config at %s for network details" ,
186+ strings .Join (availableNetworks , ", " ), cfgPath )
166187 }
167188
168189 //look for default network
@@ -182,13 +203,21 @@ func ReadConfig() (*Config, error) {
182203 }
183204
184205 if cfg .Network == nil {
185- return nil , fmt .Errorf ("default network not defined in the TOML file" )
206+ return nil , fmt .Errorf ("default network not defined in the TOML file at %s. " +
207+ "Add a network with name='%s' or specify a network using SETH_NETWORK environment variable" ,
208+ cfgPath , DefaultNetworkName )
186209 }
187210 }
188211
189212 rootPrivateKey := os .Getenv (ROOT_PRIVATE_KEY_ENV_VAR )
190213 if rootPrivateKey == "" {
191- return nil , errors .Errorf (ErrEmptyRootPrivateKey , ROOT_PRIVATE_KEY_ENV_VAR )
214+ return nil , fmt .Errorf ("no root private key was set. " +
215+ "You can provide the root private key via:\n " +
216+ " 1. %s environment variable (without 0x prefix)\n " +
217+ " 2. 'root_private_key' field in seth.toml\n " +
218+ " 3. WithPrivateKeys() when using ClientBuilder\n " +
219+ "WARNING: Never commit private keys to source control. Use environment variables or secure secret management" ,
220+ ROOT_PRIVATE_KEY_ENV_VAR )
192221 }
193222 cfg .Network .PrivateKeys = append (cfg .Network .PrivateKeys , rootPrivateKey )
194223 if cfg .Network .DialTimeout == nil {
@@ -205,7 +234,13 @@ func ReadConfig() (*Config, error) {
205234// If any configuration is invalid, it returns an error.
206235func (c * Config ) Validate () error {
207236 if c .Network == nil {
208- return errors .New (ErrNetworkIsNil )
237+ return fmt .Errorf ("network configuration is nil. " +
238+ "This usually means the network wasn't selected or configured properly.\n " +
239+ "Solutions:\n " +
240+ " 1. Set SETH_NETWORK environment variable to match a network name in seth.toml (e.g., SETH_NETWORK=sepolia)\n " +
241+ " 2. Ensure your seth.toml has a [[networks]] section with 'name' field matching SETH_NETWORK\n " +
242+ " 3. Use ClientBuilder with WithNetwork() to configure the network programmatically\n " +
243+ "See documentation for configuration examples" )
209244 }
210245
211246 if c .Network .GasPriceEstimationEnabled {
@@ -225,12 +260,20 @@ func (c *Config) Validate() error {
225260 case Priority_Slow :
226261 case Priority_Auto :
227262 default :
228- return errors .New ("when automating gas estimation is enabled priority must be auto, fast, standard or slow. fix it or disable gas estimation" )
263+ return fmt .Errorf ("invalid gas estimation priority '%s'. " +
264+ "Must be one of: 'auto', 'fast', 'standard' or 'slow'. " +
265+ "Set 'gas_price_estimation_tx_priority' in your seth.toml config. " +
266+ "To disable gas estimation, set 'gas_price_estimation_enabled = false'" ,
267+ c .Network .GasPriceEstimationTxPriority )
229268 }
230269
231270 if c .GasBump != nil && c .GasBump .Retries > 0 &&
232271 c .Network .GasPriceEstimationTxPriority == Priority_Auto {
233- return errors .New ("gas bumping is not compatible with auto priority gas estimation" )
272+ return fmt .Errorf ("configuration conflict: gas bumping (retries=%d) is not compatible with auto priority gas estimation. " +
273+ "Either:\n " +
274+ " 1. Set gas_price_estimation_tx_priority to 'fast', 'standard', or 'slow'\n " +
275+ " 2. Set gas_bump.retries = 0 to disable gas bumping" ,
276+ c .GasBump .Retries )
234277 }
235278 }
236279
@@ -254,7 +297,10 @@ func (c *Config) Validate() error {
254297 case TracingLevel_Reverted :
255298 case TracingLevel_All :
256299 default :
257- return errors .New ("tracing level must be one of: NONE, REVERTED, ALL" )
300+ return fmt .Errorf ("invalid tracing level '%s'. Must be one of: 'NONE', 'REVERTED', 'ALL'. " +
301+ "Set 'tracing_level' in your seth.toml config.\n " +
302+ "Recommended: 'REVERTED' for debugging failed transactions, 'NONE' to disable tracing completely" ,
303+ c .TracingLevel )
258304 }
259305
260306 for _ , output := range c .TraceOutputs {
@@ -263,7 +309,10 @@ func (c *Config) Validate() error {
263309 case TraceOutput_JSON :
264310 case TraceOutput_DOT :
265311 default :
266- return errors .New ("trace output must be one of: console, json, dot" )
312+ return fmt .Errorf ("invalid trace output '%s'. Must be one of: 'console', 'json', 'dot'. " +
313+ "Set 'trace_outputs' in your seth.toml config. " +
314+ "You can specify multiple outputs as an array" ,
315+ output )
267316 }
268317 }
269318
@@ -276,11 +325,18 @@ func (c *Config) Validate() error {
276325 }
277326
278327 if c .ethclient == nil && len (c .Network .URLs ) == 0 {
279- return errors .New ("at least one url should be present in config in 'secret_urls = []'" )
328+ return fmt .Errorf ("no RPC URLs configured. " +
329+ "You can provide RPC URLs via:\n " +
330+ " 1. 'urls_secret' field in seth.toml: urls_secret = [\" http://your-rpc-url\" ]\n " +
331+ " 2. WithRPCURLs() when using ClientBuilder\n " +
332+ " 3. WithEthClient() to provide a pre-configured ethclient instance" )
280333 }
281334
282335 if c .ethclient != nil && len (c .Network .URLs ) > 0 {
283- return errors .New (EthClientAndUrlsSet )
336+ return fmt .Errorf ("configuration conflict: both ethclient instance and RPC URLs are set. " +
337+ "You cannot set both. Either:\n " +
338+ " 1. Use the provided ethclient (remove 'urls_secret' from config)\n " +
339+ " 2. Use RPC URLs from config (don't provide ethclient)" )
284340 }
285341
286342 return nil
0 commit comments