seth

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2024 License: MIT Imports: 43 Imported by: 11

README

Seth

Reliable and debug-friendly Ethereum client

Decoding tests Tracing tests API tests CLI tests Integration tests (testnets)

Goals

  • Be a thin, debuggable and battle tested wrapper on top of go-ethereum
  • Decode all transaction inputs/outputs/logs for all ABIs you are working with, automatically
  • Simple synchronous API
  • Do not handle nonces on the client side, trust the server
  • Do not wrap bind generated contracts, small set of additional debug API
  • Resilient: should execute transactions even if there is a gas spike or an RPC outage (failover)
  • Well tested: should provide a suite of e2e tests that can be run on testnets to check integration

Examples

Check examples folder

Lib is providing a small amount of helpers for decoding handling that you can use with vanilla go-ethereum generated wrappers

// Decode waits for transaction and decode all the data/errors
Decode(tx *types.Transaction, txErr error) (*DecodedTransaction, error)

// NewTXOpts returns a new sequential transaction options wrapper,
// sets opts.GasPrice and opts.GasLimit from seth.toml or override with options
NewTXOpts(o ...TransactOpt) *bind.TransactOpts

// NewCallOpts returns a new call options wrapper
NewCallOpts(o ...CallOpt) *bind.CallOpts

By default, we are using the root key 0, but you can also use keys from keyfile.toml

// NewCallKeyOpts returns a new sequential call options wrapper from the key N
NewCallKeyOpts(keyNum int, o ...CallOpt) *bind.CallOpts

// NewTXKeyOpts returns a new transaction options wrapper called from the key N
NewTXKeyOpts(keyNum int, o ...TransactOpt) *bind.TransactOpts

Start Geth in a separate terminal, then run the examples

make GethSync
cd examples
go test -v

Setup

We are using nix

Enter the shell

nix develop

Building contracts

We have go-ethereum and foundry tools inside nix shell

make build

Testing

To run tests on a local network, first start it

make AnvilSync

Or use latest Geth

make GethSync

You can use default hardhat key ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 to run tests

Run the decode tests

make network=Anvil root_private_key=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 test
make network=Geth root_private_key=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 test

Check other params in seth.toml, select any network and use your key for testnets

User facing API tests are here

make network=Anvil root_private_key=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 test_api
make network=Geth root_private_key=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 test_api

CLI tests

make network=Anvil root_private_key=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 test_cli
make network=Geth root_private_key=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 test_cli

Tracing tests

make network=Anvil root_private_key=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 test_trace
make network=Geth root_private_key=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 test_trace

Config

env vars

Some crucial data is stored in env vars, create .envrc and use source .envrc, or use direnv

export SETH_LOG_LEVEL=info # global logger level
export SETH_CONFIG_PATH=seth.toml # path to the toml config
export SETH_KEYFILE_PATH=keyfile.toml # keyfile path for using multiple keys
export SETH_NETWORK=Geth # selected network
export SETH_ROOT_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 # root private key
export SETH_ONE_PASS_VAULT=712jkhjdyf71289hdjfs7d # id of 1password vault in which we store secrets

alias seth="SETH_CONFIG_PATH=seth.toml go run cmd/seth/seth.go" # useful alias for keyfile CLI

Alternatively if you don't have a network defined in the TOML you can still use the CLI by providing these 2 key env vars:

export SETH_URL=https://rpc.fuji.testnet.anyswap.exchange
export SETH_CHAIN_ID=43113

go run cmd/seth/seth.go ... # your command

In that case you should still pass network name with -n flag, especially when using CLI with 1password as network name is used when generating item name.

If SETH_KEYFILE_PATH is not set then client will create X ephemeral keys (60 by default, configurable) and won't return any funds. Use SETH_KEYFILE_PATH for testnets/mainnets and ephemeral mode only when testing against simulated network.

seth.toml

Set up your ABI directory (relative to seth.toml)

abi_dir = "contracts/abi"

Setup your BIN directory (relative to seth.toml)

bin_dir = "contracts/bin"

Decide whether you want to read keyfile or use ephemeral keys. In the first case you have two options:

  • read it from the filesystem
# If empty Seth will not try to load any keyfiles. You can either set it to 'file' to load keyfiles from
# a file (providing path to it in 'keyfile_path') or to 'base64_env' to load it from Base64-ed environment variable
# 'SETH_KEYFILE_BASE64'
keyfile_source = "file"

# If keyfile_source is set to 'file' this should be a path to a file with keyfiles
keyfile_path = "keyfile.toml"
  • read it from environment variable SETH_KEYFILE_BASE64 (keyfile needs to be base64-ed)
keyfile_source = "base64_env"

If you want to use ephemeral keys, you can set the number of keys to be generated:

# Set number of ephemeral keys to be generated (0 for no ephemeral keys). Each key will receive a proportion of native tokens from root private key's balance with the value equal to `(root_balance / ephemeral_keys_number) - transfer_fee * ephemeral_keys_number`. Using ephemeral keys together with keyfile will result in an error.
ephemeral_addresses_number = 10

You cannot use both keyfile and ephemeral keys at the same time. Trying to do so will cause configuration error.

You can enable auto-tracing for all transactions meeting configured level, which means that every time you use Decode() we will decode the transaction and also trace all calls made within the transaction, together with all inputs, outputs, logs and events. Three tracing levels are available:

  • all - trace all transactions
  • reverted - trace only reverted transactions (that's default setting used if you don't set tracing_level)
  • none - don't trace any transactions Example:
tracing_level = "reverted"

Additionally, you can decide where tracing/decoding data goes to. There are three options:

  • console - we will print all tracing data to the console
  • json - we will save tracing data for each transaction to a JSON file
  • dot - we will save tracing data for each transaction to a DOT file (graph)
trace_outputs = ["console", "json", "dot"]

For info on viewing DOT files please check the DOT graphs section below.

Example: image These two options should be used with care, when tracing_level is set to all as they might generate a lot of data.

If you want to check if the RPC is healthy on start, you can enable it with:

check_rpc_health_on_start = false

It will execute a simple check of transferring 10k wei from root key to root key and check if the transaction was successful.

You can add more networks like this:

[[Networks]]
name = "Fuji"
transaction_timeout = "30s"
# gas limit should be explicitly set only if you are connecting to a node that's incapable of estimating gas limit itself (should only happen for very old versions)
# gas_limit = 9_000_000
# hardcoded gas limit for sending funds that will be used if estimation of gas limit fails
transfer_gas_fee = 21_000
# legacy transactions
gas_price = 1_000_000_000
# EIP-1559 transactions
eip_1559_dynamic_fees = true
gas_fee_cap = 25_000_000_000
gas_tip_cap = 1_800_000_000
urls_secret = ["..."]
# if set to true we will dynamically estimate gas for every transaction (explained in more detail below)
gas_price_estimation_enabled = true
# how many last blocks to use, when estimating gas for a transaction
gas_price_estimation_blocks = 1000
# priority of the transaction, can be "fast", "standard" or "slow" (the higher the priority, the higher adjustment factor and buffer will be used for gas estimation) [default: "standard"]
gas_price_estimation_tx_priority = "slow"

If you don't we will use the default settings for Default network.

ChainID is not needed, as it's fetched from the node.

If you want to save addresses of deployed contracts, you can enable it with:

save_deployed_contracts_map = true

If you want to re-use previously deployed contracts you can indicate file name in seth.toml:

contract_map_file = "deployed_contracts_mumbai.toml"

Both features only work for live networks. Otherwise, they are ignored, and nothing is saved/read from for simulated networks.

CLI

You can either define the network you want to interact with in your TOML config and then refer it in the CLI command, or you can pass all network parameters via env vars. Most of the examples below show how to use the former approach.

Multiple keys manipulation (keyfile.toml)

To use multiple keys in your tests you can create a keyfile.toml using CLI

Set up the alias, see .envrc configuration above

export SETH_LOG_LEVEL=info # global logger level
alias seth="SETH_CONFIG_PATH=seth.toml go run cmd/seth/seth.go"

When you run any of the commands from keys namespace by default Seth will try to interact with 1password. To do that you need to meet a couple of requirements:

  1. 1password desktop app installed.
  2. 1password CLI tool called op

Now... if you are working with a vault you have access to via your desktop app, it will ask you to authenticate via the desktop app every time you need to access the vault and no further configuration is required. If it's a vault you don't have access to via the desktop app you will need to set service account token in your env vars:

export OP_SERVICE_ACCOUNT_TOKEN=...

Once you have it setup you can run op vaults list to get ids of all vaults you are assigned to. The output will look more or less like this:

ID                            NAME
4rdre3lw7mqyz4nbrqcygdzwri    Vault 1
r4qs5dh3zwofum2jse7g53cgrm    Vault 2

Once you have decided, which vault you want to use you need to export its id in SETH_ONE_PASS_VAULT variable. We will use Vault 1's ids in the following examples.

Create a new keyfile with 10 new accounts funded from the root key

SETH_ONE_PASS_VAULT=4rdre3lw7mqyz4nbrqcygdzwri SETH_ROOT_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 SETH_KEYFILE_PATH=keyfile_geth.toml seth -n Geth keys fund -a 10 [-b 2] [--local]

This will create a new Secure Note in 1password called GETH_KEYFILE with file attachment containing 10 new keys. Item name is always <NETWORK_NAME_>_KEYFILE. It's crucial that you always pass network name with -n flag, as it's used in item name. If it's missing we will use DEFAULT network name and it will be impossible to distinguish between keyfiles from different networks. SETH_KEYFILE_PATH is still required, even when using 1password, because if creating the keyfile in 1password fails, we will save it to the file, so that no funds are lost. Also remember that you don't need to define your network in TOML file as long as you pass the RPC URL with -u flag.

Run the tests, then return funds back, when needed

SETH_ONE_PASS_VAULT=4rdre3lw7mqyz4nbrqcygdzwri SETH_ROOT_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 SETH_KEYFILE_PATH=keyfile_geth.toml seth -n Geth keys return [--local]

Update the balances

SETH_ONE_PASS_VAULT=4rdre3lw7mqyz4nbrqcygdzwri  SETH_ROOT_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 SETH_KEYFILE_PATH=keyfile_geth.toml seth -n Geth keys update [--local]

Remove the keyfile

SETH_ONE_PASS_VAULT=4rdre3lw7mqyz4nbrqcygdzwri SETH_ROOT_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 SETH_KEYFILE_PATH=keyfile_geth.toml seth -n Geth keys remove [--local]

If you don't want to use 1password you can still use local keyfile by providing --local flag.

Manual gas price estimation

In order to adjust gas price for a transaction, you can use seth gas command

seth -n Fuji gas -b 10000 -tp 0.99

This will analyze last 10k blocks and give you 25/50/75/99th/Max percentiles for base fees and tip fees

-tp 0.99 requests the 99th tip percentile across all the transaction in one block and calculates 25/50/75/99th/Max across all blocks

Block stats

If you need to get some insights into network stats and create a realistic load/chaos profile with simulators (anvil as an example), you can use stats CLI command

Define your network in seth.toml

Edit your seth.toml

[[networks]]
name = "MyCustomNetwork"
urls_secret = ["..."]

[block_stats]
rpc_requests_per_second_limit = 5

Then check the stats for the last N blocks

seth -n MyCustomNetwork stats -s -10

To check stats for the interval (A, B)

seth -n MyCustomNetwork stats -s A -e B
Pass all network parameters via env vars

If you don't have a network defined in the TOML you can still use the CLI by providing the RPC url via cmd arg.

Then check the stats for the last N blocks

seth -u "https://my-rpc.network.io" stats -s -10

To check stats for the interval (A, B)

seth -u "https://my-rpc.network.io" stats -s A -e B

Results can help you to understand if network is stable, what is avg block time, gas price, block utilization and transactions per second

# Stats
perc_95_tps = 8.0
perc_95_block_duration = '3s'
perc_95_block_gas_used = 1305450
perc_95_block_gas_limit = 15000000
perc_95_block_base_fee = 25000000000
avg_tps = 2.433333333333333
avg_block_duration = '2s' 
avg_block_gas_used = 493233
avg_block_gas_limit = 15000000
avg_block_base_fee = 25000000000

# Recommended performance/chaos test parameters
duration = '2m0s'
block_gas_base_fee_initial_value = 25000000000
block_gas_base_fee_bump_percentage = '100.00% (no bump required)'
block_gas_usage_percentage = '3.28822000% gas used (no congestion)'
avg_tps = 3.0
max_tps = 8.0
Single transaction tracing

You can trace a single transaction using seth trace command. Example with seth alias mentioned before:

seth -u "https://my-rpc.network.io" trace -t 0x4c21294bf4c0a19de16e0fca74e1ea1687ba96c3cab64f6fca5640fb7b84df65

or if you want to use a predefined-network:

seth -n=Geth trace -t 0x4c21294bf4c0a19de16e0fca74e1ea1687ba96c3cab64f6fca5640fb7b84df65
Bulk tracing

You can trace multiple transactions at once using seth trace command for a predefined network named Geth. Example:

seth -n=Geth trace -f reverted_transactions.json

or by passing all the RPC parameter with a flag:

seth -u "https://my-rpc.network.io" trace -f reverted_transactions.json

You need to pass a file with a list of transaction hashes to trace. The file should be a JSON array of transaction hashes, like this:

[
  "0x...",
  "0x...",
  "0x...",
  ...
]

(Note that currently Seth automatically creates reverted_transactions_<network>_<date>.json with all reverted transactions, so you can use this file as input for the trace command.)

Features

  • Decode named inputs
  • Decode named outputs
  • Decode anonymous outputs
  • Decode logs
  • Decode indexed logs
  • Decode old string reverts
  • Decode new typed reverts
  • EIP-1559 support
  • Multi-keys client support
  • CLI to manipulate test keys
  • Simple manual gas price estimation
  • Fail over client logic
  • Decode collided event hashes
  • Tracing support (4byte)
  • Tracing support (callTracer)
  • Tracing support (prestate)
  • Tracing decoding
  • Tracing tests
  • More tests for corner cases of decoding/tracing
  • Saving of deployed contracts mapping (address -> ABI_name) for live networks
  • Reading of deployed contracts mappings for live networks
  • Automatic gas estimator (experimental)
  • Block stats CLI
  • Check if address has a pending nonce (transaction) and panic if it does
  • 1password integration for keyfiles
  • DOT graph output for tracing

You can read more about how ABI finding and contract map works here and about contract store here here.

Automatic gas estimator

This section explains how to configure and understand the automatic gas estimator, which is crucial for executing transactions on Ethereum-based networks. Here’s what you need to know:

Configuration Requirements

Before using the automatic gas estimator, it's essential to set the default gas-related parameters for your network:

  • Non-EIP-1559 Networks: Set the gas_price to define the cost per unit of gas if your network doesn't support EIP-1559.
  • EIP-1559 Networks: If your network supports EIP-1559, set the following:
    • eip_1559_dynamic_fees: Enables dynamic fee structure.
    • gas_fee_cap: The maximum fee you're willing to pay per gas.
    • gas_tip_cap: An optional tip to prioritize your transaction within a block (although if it's set to 0 there's a high chance your transaction will take longer to execute as it will be less attractive to miners, so do set it).

These settings act as a fallback if the gas estimation fails. Additionally, always specify transfer_gas_fee for the fee associated with token transfers.

If you do not know if your network supports EIP-1559, but you want to give it a try it's recommended that you also set gas_price as a fallback. When we try to use EIP-1559 during gas price estimation, but it fails, we will fallback to using non-EIP-1559 logic. If that one fails as well, we will use hardcoded gas_price value.

How Gas Estimation Works

Gas estimation varies based on whether the network is a private Ethereum Network or a live network.

  • Private Ethereum Networks: no estimation is needed. We always use hardcoded values.

For real networks, the estimation process differs for legacy transactions and those compliant with EIP-1559:

Legacy Transactions
  1. Initial Price: Query the network node for the current suggested gas price.
  2. Priority Adjustment: Modify the initial price based on gas_price_estimation_tx_priority. Higher priority increases the price to ensure faster inclusion in a block.
  3. Congestion Analysis: Examine the last X blocks (as specified by gas_price_estimation_blocks) to determine network congestion, calculating the usage rate of gas in each block and giving recent blocks more weight.
  4. Buffering: Add a buffer to the adjusted gas price to increase transaction reliability during high congestion.
EIP-1559 Transactions
  1. Tip Fee Query: Ask the node for the current recommended tip fee.
  2. Fee History Analysis: Gather the base fee and tip history from recent blocks to establish a fee baseline.
  3. Fee Selection: Use the greater of the node's suggested tip or the historical average tip for upcoming calculations.
  4. Priority and Adjustment: Increase the base and tip fees based on transaction priority (gas_price_estimation_tx_priority), which influences how much you are willing to spend to expedite your transaction.
  5. Final Fee Calculation: Sum the base fee and adjusted tip to set the gas_fee_cap.
  6. Congestion Buffer: Similar to legacy transactions, analyze congestion and apply a buffer to both the fee cap and the tip to secure transaction inclusion.

Understanding and setting these parameters correctly ensures that your transactions are processed efficiently and cost-effectively on the network.

Finally, gas_price_estimation_tx_priority is also used, when deciding, which percentile to use for base fee and tip for historical fee data. Here's how that looks:

		case Priority_Fast:
			baseFee = stats.GasPrice.Perc99
			historicalGasTipCap = stats.TipCap.Perc99
		case Priority_Standard:
			baseFee = stats.GasPrice.Perc50
			historicalGasTipCap = stats.TipCap.Perc50
		case Priority_Slow:
			baseFee = stats.GasPrice.Perc25
			historicalGasTipCap = stats.TipCap.Perc25
Adjustment factor

All values are multiplied by the adjustment factor, which is calculated based on gas_price_estimation_tx_priority:

	case Priority_Fast:
		return 1.2
	case Priority_Standard:
		return 1.0
	case Priority_Slow:
		return 0.8

For fast transactions we will increase gas price by 20%, for standard we will use the value as is and for slow we will decrease it by 20%.

Buffer percents

We further adjust the gas price by adding a buffer to it, based on congestion rate:

	case Congestion_Low:
		return 1.10, nil
	case Congestion_Medium:
		return 1.20, nil
	case Congestion_High:
		return 1.30, nil
	case Congestion_VeryHigh:
		return 1.40, nil

For low congestion rate we will increase gas price by 10%, for medium by 20%, for high by 30% and for very high by 40%.

We cache block header data in an in-memory cache, so we don't have to fetch it every time we estimate gas. The cache has capacity equal to gas_price_estimation_blocks and every time we add a new element, we remove one that is least frequently used and oldest (with block number being a constant and chain always moving forward it makes no sense to keep old blocks).

It's important to know that in order to use congestion metrics we need to fetch at least 80% of the requested blocks. If that fails, we will skip this part of the estimation and only adjust the gas price based on priority.

For both transaction types if any of the steps fails, we fallback to hardcoded values.

DOT graphs

There are multiple ways of visualising DOT graphs:

  • xdot application [recommended]
  • VSCode Extensions
  • online viewers
xdot

To install simply run homebrew install xdot and then run xdot <path_to_dot_file>. This tool seems to be the best for the job, since the viewer is interactive and supports tooltips, which in our case contain extra tracing information.

VSCode Extensions

There are multiple extensions that can be used to view DOT files in VSCode. We recommend using Graphviz Preview. The downside is that it doesn't support tooltips.

Goland

We were unable to find any (working) plugins for DOT graph visualization. If you do know any, please let us know.

Online viewers

There's at least a dozen of them available, but none of them support tooltips and most can't handle our multi-line labels. These two are known to work, though:

Experimental features

In order to enable an experimental feature you need to pass it's name in config. It's a global config, you cannot enable it per-network. Example:

# other settings before...
tracing_level = "reverted"
trace_outputs = ["console"]
experiments_enabled = ["slow_funds_return", "eip_1559_fee_equalizer"]

Here's what they do:

  • slow_funds_return will work only in core and when enabled it changes tx priority to slow and increases transaction timeout to 30 minutes.
  • eip_1559_fee_equalizer in case of EIP-1559 transactions if it detects that historical base fee and suggested/historical tip are more than 3 orders of magnitude apart, it will use the higher value for both (this helps in cases where base fee is almost 0 and transaction is never processed).

Documentation

Index

Constants

View Source
const (
	ErrEmptyConfigPath      = "toml config path is empty, set SETH_CONFIG_PATH"
	ErrCreateABIStore       = "failed to create ABI store"
	ErrReadingKeys          = "failed to read keys"
	ErrCreateNonceManager   = "failed to create nonce manager"
	ErrCreateTracer         = "failed to create tracer"
	ErrReadContractMap      = "failed to read deployed contract map"
	ErrNoKeyLoaded          = "failed to load private key"
	ErrRpcHealthCheckFailed = "RPC health check failed ¯\\_(ツ)_/¯"

	ContractMapFilePattern          = "deployed_contracts_%s_%s.toml"
	RevertedTransactionsFilePattern = "reverted_transactions_%s_%s.json"
)
View Source
const (
	ErrReadSethConfig         = "failed to read TOML config for seth"
	ErrReadKeyFileConfig      = "failed to read TOML keyfile config"
	ErrUnmarshalSethConfig    = "failed to unmarshal TOML config for seth"
	ErrUnmarshalKeyFileConfig = "failed to unmarshal TOML keyfile config for seth"
	ErrEmptyRootPrivateKey    = "no private keys were set, set %s=..."

	GETH  = "Geth"
	ANVIL = "Anvil"

	CONFIG_FILE_ENV_VAR    = "SETH_CONFIG_PATH"
	KEYFILE_BASE64_ENV_VAR = "SETH_KEYFILE_BASE64"
	KEYFILE_PATH_ENV_VAR   = "SETH_KEYFILE_PATH"

	ROOT_PRIVATE_KEY_ENV_VAR = "SETH_ROOT_PRIVATE_KEY"
	NETWORK_ENV_VAR          = "SETH_NETWORK"
	URL_ENV_VAR              = "SETH_URL"

	ONE_PASS_VAULT_ENV_VAR = "SETH_ONE_PASS_VAULT"

	DefaultNetworkName = "Default"
)
View Source
const (
	Experiment_SlowFundsReturn    = "slow_funds_return"
	Experiment_Eip1559FeeEqualier = "eip_1559_fee_equalizer"
)
View Source
const (
	ErrOpenABIFile = "failed to open ABI file"
	ErrParseABI    = "failed to parse ABI file"
	ErrOpenBINFile = "failed to open BIN file"
)
View Source
const (
	ErrDecodeInput          = "failed to decode transaction input"
	ErrDecodeOutput         = "failed to decode transaction output"
	ErrDecodeLog            = "failed to decode log"
	ErrDecodedLogNonIndexed = "failed to decode non-indexed log data"
	ErrDecodeILogIndexed    = "failed to decode indexed log data"
	ErrNoTxData             = "no tx data or it's less than 4 bytes"
	ErrRPCJSONCastError     = "failed to cast CallMsg error as rpc.DataError"

	WarnNoContractStore = "ContractStore is nil, use seth.NewContractStore(...) to decode transactions"
)
View Source
const (
	Priority_Degen    = "degen" //this is undocumented option, which we left for cases, when we need to set the highest gas price
	Priority_Fast     = "fast"
	Priority_Standard = "standard"
	Priority_Slow     = "slow"

	Congestion_Low      = "low"
	Congestion_Medium   = "medium"
	Congestion_High     = "high"
	Congestion_VeryHigh = "extreme"
)
View Source
const (
	// each block has the same weight in the computation
	CongestionStrategy_Simple = "simple"
	// newer blocks have more weight in the computation
	CongestionStrategy_NewestFirst = "newest_first"
)
View Source
const (
	ErrKeySyncTimeout = "key sync timeout, consider increasing key_sync_timeout in seth.toml, or increasing the number of keys"
	ErrKeySync        = "failed to sync the key"
	ErrNonce          = "failed to get nonce"
	TimeoutKeyNum     = -80001
)
View Source
const (
	ErrNoTrace                = "no trace found"
	ErrNoABIMethod            = "no ABI method found"
	ErrNoAbiFound             = "no ABI found in Contract Store"
	ErrNoFourByteFound        = "no method signatures found in tracing data"
	ErrInvalidMethodSignature = "no method signature found or it's not 4 bytes long"
	WrnMissingCallTrace       = "" /* 135-byte string literal not displayed */

	FAILED_TO_DECODE = "failed to decode"
	UNKNOWN          = "unknown"
	NO_DATA          = "no data"

	CommentMissingABI = "Call not decoded due to missing ABI instance"
)
View Source
const (
	ErrEmptyKeyFile               = "keyfile is empty"
	ErrInsufficientRootKeyBalance = "insufficient root key balance: %s"
)
View Source
const (
	MetadataNotFoundErr       = "metadata section not found"
	InvalidMetadataLengthErr  = "invalid metadata length"
	FailedToDecodeMetadataErr = "failed to decode metadata"
	NotCompiledWithSolcErr    = "not compiled with solc"
)
View Source
const (
	ErrRPCConnectionRefused = "connection refused"
)
View Source
const (
	ErrRetryTimeout = "retry timeout"
)
View Source
const (
	LogLevelEnvVar = "SETH_LOG_LEVEL"
)

Variables

View Source
var (
	// Amount of funds that will be left on the root key, when splitting funds between ephemeral addresses
	ZeroInt64 int64 = 0

	TracingLevel_None     = "NONE"
	TracingLevel_Reverted = "REVERTED"
	TracingLevel_All      = "ALL"

	TraceOutput_Console = "console"
	TraceOutput_JSON    = "json"
	TraceOutput_DOT     = "dot"
)
View Source
var (
	ZeroGasSuggestedErr = "either base fee or suggested tip is 0"
	BlockFetchingErr    = "failed to fetch enough block headers for congestion calculation"
)

Functions

func CreateIn1Pass added in v1.0.12

func CreateIn1Pass(c *Client, content string, vaultId string) error

CreateIn1Pass creates a new keyfile in 1Password. If a keyfile with the same name already exists we will return an error. Keyfile will be added as a file attachment to a Secure Note in the specified vault.

func CreateOrAppendToJsonArray added in v0.1.2

func CreateOrAppendToJsonArray(filePath string, newItem any) error

CreateOrAppendToJsonArray appends to a JSON array in a file or creates a new JSON array if the file is empty or doesn't exist

func DeleteFrom1Pass added in v1.0.12

func DeleteFrom1Pass(c *Client, vaultId string) error

func DoesPragmaSupportCustomRevert added in v1.0.10

func DoesPragmaSupportCustomRevert(pragma Pragma) bool

DoesPragmaSupportCustomRevert checks if the pragma version supports custom revert messages (must be >= 0.8.4)

func EtherToWei added in v0.1.3

func EtherToWei(eth *big.Float) *big.Int

EtherToWei converts an ETH float amount to wei

func ExistsIn1Pass added in v1.0.12

func ExistsIn1Pass(c *Client, vaultId string) (bool, error)

ExistsIn1Pass checks if a keyfile exists in the specified vault.

func LoadDeployedContracts

func LoadDeployedContracts(filename string) (map[string]string, error)

func NewAddress

func NewAddress() (string, string, error)

NewAddress creates a new address

func NewEphemeralKeys

func NewEphemeralKeys(addrs int64) ([]string, error)

NewEphemeralKeys creates a new ephemeral keyfile, can be used for simulated networks

func OpenJsonFileAsStruct added in v0.1.2

func OpenJsonFileAsStruct(path string, v any) error

func ReplaceIn1Pass added in v1.0.12

func ReplaceIn1Pass(c *Client, content string, vaultId string) error

ReplaceIn1Pass replaces the keyfile in 1Password. If a keyfile with the same name does not exist it will return an error.

func ReturnFunds

func ReturnFunds(c *Client, toAddr string) error

ReturnFunds returns funds to the root key from all other keys

func ReturnFundsFromKeyFileAndUpdateIt added in v1.0.12

func ReturnFundsFromKeyFileAndUpdateIt(c *Client, toAddr string, opts *FundKeyFileCmdOpts) error

ReturnFundsFromKeyFileAndUpdateIt returns funds to the root key from all the test keys in keyfile (local or loaded from 1password) and updates the keyfile with the new balances

func SaveDeployedContract

func SaveDeployedContract(filename, contractName, address string) error

func UpdateAndSplitFunds

func UpdateAndSplitFunds(c *Client, opts *FundKeyFileCmdOpts) error

UpdateAndSplitFunds splits funds from the root key into equal parts. If keyfile already exists it doesn't generate new keys, but uses existing ones. By default, it saves/read keyfile from 1Password. If you want to save it locally set opts.LocalKeyfile to true.

func UpdateKeyFileBalances

func UpdateKeyFileBalances(c *Client, opts *FundKeyFileCmdOpts) error

UpdateKeyFileBalances updates file balances for private keys stored in either local keyfile or 1password

func ValidateConfig added in v1.0.10

func ValidateConfig(cfg *Config) error

func WeiToEther added in v0.1.3

func WeiToEther(wei *big.Int) *big.Float

WeiToEther converts a wei amount to eth float

Types

type ABIFinder

type ABIFinder struct {
	ContractMap   ContractMap
	ContractStore *ContractStore
}

func NewABIFinder

func NewABIFinder(contractMap ContractMap, contractStore *ContractStore) ABIFinder

func (*ABIFinder) FindABIByMethod

func (a *ABIFinder) FindABIByMethod(address string, signature []byte) (ABIFinderResult, error)

FindABIByMethod finds the ABI method and instance for the given contract address and signature If the contract address is known, it will use the ABI instance that is known to be at the address. If the contract address is not known, it will iterate over all known ABIs and check if any of them has a method with the given signature. If there are duplicates we will use the first ABI that matched.

type ABIFinderResult

type ABIFinderResult struct {
	ABI            abi.ABI
	Method         *abi.Method
	DuplicateCount int
	// contains filtered or unexported fields
}

func (*ABIFinderResult) ContractName

func (a *ABIFinderResult) ContractName() string

type ABIStore

type ABIStore map[string]abi.ABI

type BlockStats added in v1.0.10

type BlockStats struct {
	Limiter ratelimit.Limiter
	Client  *Client
}

BlockStats is a block stats calculator

func NewBlockStats added in v1.0.10

func NewBlockStats(c *Client) (*BlockStats, error)

NewBlockStats creates a new instance of BlockStats

func (*BlockStats) CalculateBlockDurations added in v1.0.10

func (cs *BlockStats) CalculateBlockDurations(blocks []*types.Block) error

CalculateBlockDurations calculates and logs the duration, TPS, gas used, and gas limit between each consecutive block

func (*BlockStats) Stats added in v1.0.10

func (cs *BlockStats) Stats(startBlock *big.Int, endBlock *big.Int) error

Stats fetches and logs the blocks' statistics from startBlock to endBlock

type BlockStatsConfig added in v1.0.10

type BlockStatsConfig struct {
	RPCRateLimit int `toml:"rpc_requests_per_second_limit"`
}

func (*BlockStatsConfig) Validate added in v1.0.10

func (cfg *BlockStatsConfig) Validate() error

type Call

type Call struct {
	From    string     `json:"from"`
	Gas     string     `json:"gas"`
	GasUsed string     `json:"gasUsed"`
	Input   string     `json:"input"`
	Logs    []TraceLog `json:"logs"`
	Output  string     `json:"output"`
	To      string     `json:"to"`
	Type    string     `json:"type"`
	Value   string     `json:"value"`
	Error   string     `json:"error"`
	Calls   []Call     `json:"calls"`
}

type CallOpt

type CallOpt func(o *bind.CallOpts)

CallOpt is a functional option for bind.CallOpts

func WithBlockNumber

func WithBlockNumber(bn uint64) CallOpt

WithBlockNumber sets blockNumber option for bind.CallOpts

func WithPending

func WithPending(pending bool) CallOpt

WithPending sets pending option for bind.CallOpts

type Client

type Client struct {
	Cfg                      *Config
	Client                   *ethclient.Client
	Addresses                []common.Address
	PrivateKeys              []*ecdsa.PrivateKey
	ChainID                  int64
	URL                      string
	Context                  context.Context
	CancelFunc               context.CancelFunc
	Errors                   []error
	ContractStore            *ContractStore
	NonceManager             *NonceManager
	Tracer                   *Tracer
	ContractAddressToNameMap ContractMap
	ABIFinder                *ABIFinder
	HeaderCache              *LFUHeaderCache
}

Client is a vanilla go-ethereum client with enhanced debug logging

func NewClient

func NewClient() (*Client, error)

NewClient creates a new raw seth client with all deps setup from env vars

func NewClientRaw

func NewClientRaw(
	cfg *Config,
	addrs []common.Address,
	pkeys []*ecdsa.PrivateKey,
	opts ...ClientOpt,
) (*Client, error)

NewClientRaw creates a new raw seth client without dependencies

func NewClientWithConfig

func NewClientWithConfig(cfg *Config) (*Client, error)

NewClientWithConfig creates a new seth client with all deps setup from config

func (*Client) AnySyncedKey

func (m *Client) AnySyncedKey() int

AnySyncedKey returns the first synced key

func (*Client) CalculateGasEstimations added in v0.1.3

func (m *Client) CalculateGasEstimations(request GasEstimationRequest) GasEstimations

CalculateGasEstimations calculates gas estimations (price, tip/cap) or uses hardcoded values if estimation is disabled, estimation errors or network is a simulated one.

func (*Client) CalculateNetworkCongestionMetric added in v0.1.3

func (m *Client) CalculateNetworkCongestionMetric(blocksNumber uint64, strategy string) (float64, error)

CalculateNetworkCongestionMetric calculates a simple congestion metric based on the last N blocks according to selected strategy.

func (*Client) CalculateSubKeyFunding

func (m *Client) CalculateSubKeyFunding(addrs, gasPrice, rooKeyBuffer int64) (*FundingDetails, error)

CalculateSubKeyFunding calculates all required params to split funds from the root key to N test keys

func (*Client) CallMsgFromTx

func (m *Client) CallMsgFromTx(tx *types.Transaction) (ethereum.CallMsg, error)

CallMsgFromTx creates ethereum.CallMsg from tx, used in simulated calls

func (*Client) CreateOrUnmarshalKeyFile

func (m *Client) CreateOrUnmarshalKeyFile(opts *FundKeyFileCmdOpts) (*KeyFile, KeyfileStatus, error)

func (*Client) Decode

func (m *Client) Decode(tx *types.Transaction, txErr error) (*DecodedTransaction, error)

Decode waits for transaction to be minted, then decodes transaction inputs, outputs, logs and events and depending on 'tracing_level' it either returns immediatelly or if the level matches it traces all calls. If 'tracing_to_json' is saved we also save to JSON all that information. If transaction was reverted the error return will be revert error, not decoding error (that one if any will be logged). It means it can return both error and decoded transaction!

func (*Client) DecodeCustomABIErr

func (m *Client) DecodeCustomABIErr(txErr error) (string, error)

DecodeCustomABIErr decodes typed Solidity errors

func (*Client) DeployContract

func (m *Client) DeployContract(auth *bind.TransactOpts, name string, abi abi.ABI, bytecode []byte, params ...interface{}) (DeploymentData, error)

DeployContract deploys contract using ABI and bytecode passed to it, waits for transaction to be minted and contract really available at the address, so that when the method returns it's safe to interact with it. It also saves the contract address and ABI name to the contract map, so that we can use that, when tracing transactions. It is suggested to use name identical to the name of the contract Solidity file.

func (*Client) DeployContractFromContractStore

func (m *Client) DeployContractFromContractStore(auth *bind.TransactOpts, name string, params ...interface{}) (DeploymentData, error)

DeployContractFromContractStore deploys contract from Seth's Contract Store, waits for transaction to be minted and contract really available at the address, so that when the method returns it's safe to interact with it. It also saves the contract address and ABI name to the contract map, so that we can use that, when tracing transactions. Name by which you refer the contract should be the same as the name of ABI file (you can omit the .abi suffix).

func (*Client) DeployDebugContract

func (m *Client) DeployDebugContract(subDbgAddr common.Address) (*network_debug_contract.NetworkDebugContract, common.Address, error)

func (*Client) DownloadContractAndGetPragma added in v1.0.10

func (m *Client) DownloadContractAndGetPragma(address common.Address, block *big.Int) (Pragma, error)

func (*Client) EstimateGasLimitForFundTransfer added in v1.0.7

func (m *Client) EstimateGasLimitForFundTransfer(from, to common.Address, amount *big.Int) (uint64, error)

EstimateGasLimitForFundTransfer estimates gas limit for fund transfer

func (*Client) GetRootKeyAddress added in v1.0.9

func (m *Client) GetRootKeyAddress() (common.Address, error)

GetRootKeyAddress returns the root key address from the client configuration. If no addresses are found, it returns an error. Root key address is the first address in the list of addresses.

func (*Client) GetRootPrivateKey added in v1.0.10

func (m *Client) GetRootPrivateKey() (*ecdsa.PrivateKey, error)

GetRootPrivateKey returns the private key of root key/address from the client configuration. If no private keys are found, it returns an error. Root private key is the first private key in the list of private keys.

func (*Client) GetSuggestedEIP1559Fees added in v0.1.3

func (m *Client) GetSuggestedEIP1559Fees(ctx context.Context, priority string) (maxFeeCap *big.Int, adjustedTipCap *big.Int, err error)

GetSuggestedEIP1559Fees returns suggested tip/fee cap calculated based on historical data, current congestion, and priority.

func (*Client) GetSuggestedLegacyFees added in v0.1.3

func (m *Client) GetSuggestedLegacyFees(ctx context.Context, priority string) (adjustedGasPrice *big.Int, err error)

GetSuggestedLegacyFees calculates the suggested gas price based on historical data, current congestion, and priority.

func (*Client) HistoricalFeeData added in v0.1.3

func (m *Client) HistoricalFeeData(priority string) (baseFee float64, historicalGasTipCap float64, err error)

func (*Client) MustGetRootKeyAddress added in v1.0.9

func (m *Client) MustGetRootKeyAddress() common.Address

MustGetRootKeyAddress returns the root key address from the client configuration. If no addresses are found, it panics. Root key address is the first address in the list of addresses.

func (*Client) MustGetRootPrivateKey added in v1.0.10

func (m *Client) MustGetRootPrivateKey() *ecdsa.PrivateKey

MustGetRootPrivateKey returns the private key of root key/address from the client configuration. If no private keys are found, it panics. Root private key is the first private key in the list of private keys.

func (*Client) NewCallKeyOpts

func (m *Client) NewCallKeyOpts(keyNum int, o ...CallOpt) *bind.CallOpts

NewCallKeyOpts returns a new sequential call options wrapper from the key N

func (*Client) NewCallOpts

func (m *Client) NewCallOpts(o ...CallOpt) *bind.CallOpts

NewCallOpts returns a new sequential call options wrapper

func (*Client) NewDefaultGasEstimationRequest added in v1.0.7

func (m *Client) NewDefaultGasEstimationRequest() GasEstimationRequest

NewDefaultGasEstimationRequest creates a new default gas estimation request based on current network configuration

func (*Client) NewTXKeyOpts

func (m *Client) NewTXKeyOpts(keyNum int, o ...TransactOpt) *bind.TransactOpts

NewTXKeyOpts returns a new transaction options wrapper, sets opts.GasPrice and opts.GasLimit from seth.toml or override with options

func (*Client) NewTXOpts

func (m *Client) NewTXOpts(o ...TransactOpt) *bind.TransactOpts

NewTXOpts returns a new transaction options wrapper, Sets gas price/fee tip/cap and gas limit either based on TOML config or estimations.

func (*Client) RetryTxAndDecode

func (m *Client) RetryTxAndDecode(f func() (*types.Transaction, error)) (*DecodedTransaction, error)

RetryTxAndDecode executes transaction several times, retries if connection is lost and decodes all the data

func (*Client) SaveDecodedCallsAsJson

func (m *Client) SaveDecodedCallsAsJson(dirname string) error

func (*Client) TransferETHFromKey

func (m *Client) TransferETHFromKey(ctx context.Context, fromKeyNum int, to string, value *big.Int, gasPrice *big.Int) error

func (*Client) WaitMined

WaitMined the same as bind.WaitMined, awaits transaction receipt until timeout

type ClientOpt

type ClientOpt func(c *Client)

ClientOpt is a client functional option

func WithABIFinder

func WithABIFinder(abiFinder *ABIFinder) ClientOpt

WithABIFinder ABIFinder functional option

func WithContractMap

func WithContractMap(contractAddressToNameMap ContractMap) ClientOpt

WithContractMap contractAddressToNameMap functional option

func WithContractStore

func WithContractStore(as *ContractStore) ClientOpt

WithContractStore ContractStore functional option

func WithNonceManager

func WithNonceManager(nm *NonceManager) ClientOpt

WithNonceManager NonceManager functional option

func WithTracer

func WithTracer(t *Tracer) ClientOpt

WithTracer Tracer functional option

type CommonData

type CommonData struct {
	CallType        string                 `json:"call_type,omitempty"`
	Signature       string                 `json:"signature"`
	Method          string                 `json:"method"`
	Input           map[string]interface{} `json:"input,omitempty"`
	Output          map[string]interface{} `json:"output,omitempty"`
	NestingLevel    int                    `json:"nesting_level,omitempty"`
	ParentSignature string                 `json:"parent_signature,omitempty"`
	Error           string                 `json:"error,omitempty"`
}

type Config

type Config struct {
	// internal fields
	RevertedTransactionsFile string

	// external fields
	KeyFileSource                 KeyFileSource     `toml:"keyfile_source"`
	KeyFilePath                   string            `toml:"keyfile_path"`
	EphemeralAddrs                *int64            `toml:"ephemeral_addresses_number"`
	RootKeyFundsBuffer            *int64            `toml:"root_key_funds_buffer"`
	ABIDir                        string            `toml:"abi_dir"`
	BINDir                        string            `toml:"bin_dir"`
	ContractMapFile               string            `toml:"contract_map_file"`
	SaveDeployedContractsMap      bool              `toml:"save_deployed_contracts_map"`
	Network                       *Network          `toml:"network"`
	Networks                      []*Network        `toml:"networks"`
	NonceManager                  *NonceManagerCfg  `toml:"nonce_manager"`
	TracingLevel                  string            `toml:"tracing_level"`
	TraceOutputs                  []string          `toml:"trace_outputs"`
	PendingNonceProtectionEnabled bool              `toml:"pending_nonce_protection_enabled"`
	ConfigDir                     string            `toml:"abs_path"`
	ExperimentsEnabled            []string          `toml:"experiments_enabled"`
	CheckRpcHealthOnStart         bool              `toml:"check_rpc_health_on_start"`
	BlockStatsConfig              *BlockStatsConfig `toml:"block_stats"`
	// contains filtered or unexported fields
}

func ReadConfig

func ReadConfig() (*Config, error)

ReadConfig reads the TOML config file from location specified by env var "SETH_CONFIG_PATH" and returns a Config struct

func (*Config) GenerateContractMapFileName

func (c *Config) GenerateContractMapFileName() string

GenerateContractMapFileName generates a file name for the contract map

func (*Config) GetMaxConcurrency added in v1.0.7

func (c *Config) GetMaxConcurrency() int

GetMaxConcurrency returns the maximum number of concurrent transactions. Root key is excluded from the count.

func (*Config) IsExperimentEnabled added in v0.1.3

func (c *Config) IsExperimentEnabled(experiment string) bool

func (*Config) IsSimulatedNetwork

func (c *Config) IsSimulatedNetwork() bool

IsSimulatedNetwork returns true if the network is simulated (i.e. Geth or Anvil)

func (*Config) ParseKeys

func (c *Config) ParseKeys() ([]common.Address, []*ecdsa.PrivateKey, error)

ParseKeys parses private keys from the config

func (*Config) ShoulSaveDeployedContractMap added in v0.1.1

func (c *Config) ShoulSaveDeployedContractMap() bool

ShoulSaveDeployedContractMap returns true if the contract map should be saved (i.e. not a simulated network and functionality is enabled)

type ContextErrorKey added in v1.0.7

type ContextErrorKey struct{}

type ContractLoader added in v1.0.10

type ContractLoader[T any] struct {
	Client *Client
}

ContractLoader is a helper struct for loading contracts

func NewContractLoader added in v1.0.10

func NewContractLoader[T any](client *Client) *ContractLoader[T]

NewContractLoader creates a new contract loader

func (*ContractLoader[T]) LoadContract added in v1.0.10

func (cl *ContractLoader[T]) LoadContract(name string, address common.Address, abiLoadFn func() (*abi.ABI, error), wrapperInitFn func(common.Address, bind.ContractBackend) (*T, error)) (*T, error)

LoadContract loads contract by name, address, ABI loader and wrapper init function, it adds contract ABI to Seth Contract Store and address to Contract Map. Thanks to that we can easily trace and debug interactions with the contract. Signatures of functions passed to this method were chosen to conform to Geth wrappers' GetAbi() and NewXXXContract() functions.

type ContractMap

type ContractMap struct {
	// contains filtered or unexported fields
}

func NewContractMap added in v1.0.7

func NewContractMap(contracts map[string]string) ContractMap

func NewEmptyContractMap added in v1.0.7

func NewEmptyContractMap() ContractMap

func (ContractMap) AddContract

func (c ContractMap) AddContract(addr, name string)

func (ContractMap) GetContractAddress

func (c ContractMap) GetContractAddress(addr string) string

func (ContractMap) GetContractMap added in v1.0.7

func (c ContractMap) GetContractMap() map[string]string

func (ContractMap) GetContractName

func (c ContractMap) GetContractName(addr string) string

func (ContractMap) IsKnownAddress

func (c ContractMap) IsKnownAddress(addr string) bool

func (ContractMap) Size added in v1.0.7

func (c ContractMap) Size() int

type ContractStore

type ContractStore struct {
	ABIs ABIStore
	BINs map[string][]byte
	// contains filtered or unexported fields
}

ContractStore contains all ABIs that are used in decoding. It might also contain contract bytecode for deployment

func NewContractStore

func NewContractStore(abiPath, binPath string) (*ContractStore, error)

NewContractStore creates a new Contract store

func (*ContractStore) AddABI

func (c *ContractStore) AddABI(name string, abi abi.ABI)

func (*ContractStore) AddBIN

func (c *ContractStore) AddBIN(name string, bin []byte)

func (*ContractStore) GetABI

func (c *ContractStore) GetABI(name string) (*abi.ABI, bool)

func (*ContractStore) GetBIN

func (c *ContractStore) GetBIN(name string) ([]byte, bool)

type DecodableLog

type DecodableLog interface {
	GetTopics() []common.Hash
	GetData() []byte
}

type DecodedCall

type DecodedCall struct {
	CommonData
	FromAddress string             `json:"from_address,omitempty"`
	ToAddress   string             `json:"to_address,omitempty"`
	From        string             `json:"from,omitempty"`
	To          string             `json:"to,omitempty"`
	Events      []DecodedCommonLog `json:"events,omitempty"`
	Comment     string             `json:"comment,omitempty"`
	Value       int64              `json:"value,omitempty"`
	GasLimit    uint64             `json:"gas_limit,omitempty"`
	GasUsed     uint64             `json:"gas_used,omitempty"`
}

DecodedCall decoded call

type DecodedCommonLog

type DecodedCommonLog struct {
	Signature string                 `json:"signature"`
	Address   common.Address         `json:"address"`
	EventData map[string]interface{} `json:"event_data"`
	Topics    []string               `json:"topics,omitempty"`
}

func (*DecodedCommonLog) MergeEventData

func (d *DecodedCommonLog) MergeEventData(newEventData map[string]interface{})

type DecodedTransaction

type DecodedTransaction struct {
	CommonData
	Index       uint                    `json:"index"`
	Hash        string                  `json:"hash,omitempty"`
	Protected   bool                    `json:"protected,omitempty"`
	Transaction *types.Transaction      `json:"transaction,omitempty"`
	Receipt     *types.Receipt          `json:"receipt,omitempty"`
	Events      []DecodedTransactionLog `json:"events,omitempty"`
}

DecodedTransaction decoded transaction

type DecodedTransactionLog

type DecodedTransactionLog struct {
	DecodedCommonLog
	BlockNumber uint64 `json:"block_number"`
	Index       uint   `json:"index"`
	TXHash      string `json:"hash"`
	TXIndex     uint   `json:"tx_index"`
	Removed     bool   `json:"removed"`
	FileTag     string `json:"file_tag,omitempty"`
}

DecodedTransactionLog decoded Solidity log(event)

func (*DecodedTransactionLog) MergeEventData

func (d *DecodedTransactionLog) MergeEventData(newEventData map[string]interface{})

type DeploymentData

type DeploymentData struct {
	Address       common.Address
	Transaction   *types.Transaction
	BoundContract *bind.BoundContract
}

type Duration

type Duration struct{ D time.Duration }

Duration is a non-negative time duration.

func MakeDuration

func MakeDuration(d time.Duration) (Duration, error)

func MustMakeDuration

func MustMakeDuration(d time.Duration) *Duration

func ParseDuration

func ParseDuration(s string) (Duration, error)

func (Duration) Before

func (d Duration) Before(t time.Time) time.Time

Before returns the time d units before time t

func (Duration) Duration

func (d Duration) Duration() time.Duration

Duration returns the value as the standard time.Duration value.

func (Duration) IsInstant

func (d Duration) IsInstant() bool

IsInstant is true if and only if d is of duration 0

func (Duration) MarshalJSON

func (d Duration) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (Duration) MarshalText

func (d Duration) MarshalText() ([]byte, error)

MarshalText implements the text.Marshaler interface.

func (*Duration) Scan

func (d *Duration) Scan(v interface{}) (err error)

func (Duration) Shorter

func (d Duration) Shorter(od Duration) bool

Shorter returns true if and only if d is shorter than od.

func (Duration) String

func (d Duration) String() string

String returns a string representing the duration in the form "72h3m0.5s". Leading zero units are omitted. As a special case, durations less than one second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure that the leading digit is non-zero. The zero duration formats as 0s.

func (*Duration) UnmarshalJSON

func (d *Duration) UnmarshalJSON(input []byte) error

UnmarshalJSON implements the json.Unmarshaler interface.

func (*Duration) UnmarshalText

func (d *Duration) UnmarshalText(input []byte) error

UnmarshalText implements the text.Unmarshaler interface.

func (Duration) Value

func (d Duration) Value() (driver.Value, error)

type FundKeyFileCmdOpts

type FundKeyFileCmdOpts struct {
	Addrs         int64
	RootKeyBuffer int64
	LocalKeyfile  bool
	VaultId       string
}

FundKeyFileCmdOpts funding params for CLI

type FundingDetails

type FundingDetails struct {
	RootBalance        *big.Int
	TotalFee           *big.Int
	FreeBalance        *big.Int
	AddrFunding        *big.Int
	NetworkTransferFee int64
}

FundingDetails funding details about shares we put into test keys

type GasEstimationRequest added in v0.1.3

type GasEstimationRequest struct {
	GasEstimationEnabled bool
	FallbackGasPrice     int64
	FallbackGasFeeCap    int64
	FallbackGasTipCap    int64
	Priority             string
}

type GasEstimations added in v0.1.3

type GasEstimations struct {
	GasPrice  *big.Int
	GasTipCap *big.Int
	GasFeeCap *big.Int
}

type GasEstimator

type GasEstimator struct {
	Client              *Client
	BlockGasLimits      []uint64
	TransactionGasPrice []uint64
}

GasEstimator estimates gas prices

func NewGasEstimator

func NewGasEstimator(c *Client) *GasEstimator

NewGasEstimator creates a new gas estimator

func (*GasEstimator) Stats

func (m *GasEstimator) Stats(fromNumber uint64, priorityPerc float64) (GasSuggestions, error)

Stats prints gas stats

type GasPercentiles

type GasPercentiles struct {
	Max    float64
	Perc99 float64
	Perc75 float64
	Perc50 float64
	Perc25 float64
}

GasPercentiles contains gas percentiles

type GasSuggestions

type GasSuggestions struct {
	GasPrice           *GasPercentiles
	TipCap             *GasPercentiles
	SuggestedGasPrice  *big.Int
	SuggestedGasTipCap *big.Int
}

type KeyData

type KeyData struct {
	PrivateKey string `toml:"private_key"`
	Address    string `toml:"address"`
	Funds      string `toml:"funds"`
}

KeyData data for test keys

type KeyFile

type KeyFile struct {
	Keys []*KeyData `toml:"keys"`
}

KeyFile is a struct that holds all test keys data

func LoadFrom1Pass added in v1.0.12

func LoadFrom1Pass(c *Client, vaultId string) (KeyFile, error)

LoadFrom1Pass loads a keyfile from 1Password. If the keyfile does not exist it will return an error.

func NewKeyFile

func NewKeyFile() *KeyFile

type KeyFileSource added in v1.0.10

type KeyFileSource string
const (
	KeyFileSourceBase64EnvVar KeyFileSource = "base64_env"
	KeyFileSourceFile         KeyFileSource = "file"
)

type KeyNonce

type KeyNonce struct {
	KeyNum int
	Nonce  uint64
}

type KeyfileStatus added in v1.0.12

type KeyfileStatus = bool
const (
	NewKeyfile      KeyfileStatus = true
	ExistingKeyfile KeyfileStatus = false
)

type LFUHeaderCache added in v0.1.3

type LFUHeaderCache struct {
	// contains filtered or unexported fields
}

LFUHeaderCache is a Least Frequently Used header cache

func NewLFUBlockCache added in v0.1.3

func NewLFUBlockCache(capacity uint64) *LFUHeaderCache

NewLFUBlockCache creates a new LFU cache with the given capacity.

func (*LFUHeaderCache) Get added in v0.1.3

func (c *LFUHeaderCache) Get(blockNumber int64) (*types.Header, bool)

Get retrieves a header from the cache.

func (*LFUHeaderCache) Set added in v0.1.3

func (c *LFUHeaderCache) Set(header *types.Header) error

Set adds or updates a header in the cache.

type LogWithEventData

type LogWithEventData interface {
	MergeEventData(map[string]interface{})
}

type Network

type Network struct {
	Name                         string    `toml:"name"`
	URLs                         []string  `toml:"urls_secret"`
	EIP1559DynamicFees           bool      `toml:"eip_1559_dynamic_fees"`
	GasPrice                     int64     `toml:"gas_price"`
	GasFeeCap                    int64     `toml:"gas_fee_cap"`
	GasTipCap                    int64     `toml:"gas_tip_cap"`
	GasLimit                     uint64    `toml:"gas_limit"`
	TxnTimeout                   *Duration `toml:"transaction_timeout"`
	TransferGasFee               int64     `toml:"transfer_gas_fee"`
	PrivateKeys                  []string  `toml:"private_keys_secret"`
	GasPriceEstimationEnabled    bool      `toml:"gas_price_estimation_enabled"`
	GasPriceEstimationBlocks     uint64    `toml:"gas_price_estimation_blocks"`
	GasPriceEstimationTxPriority string    `toml:"gas_price_estimation_tx_priority"`

	// derivative vars
	ChainID string
}

type NonceManager

type NonceManager struct {
	*sync.Mutex

	Client      *Client
	SyncTimeout time.Duration
	SyncedKeys  chan *KeyNonce
	Addresses   []common.Address
	PrivateKeys []*ecdsa.PrivateKey
	Nonces      map[common.Address]int64
	// contains filtered or unexported fields
}

NonceManager tracks nonce for each address

func NewNonceManager

func NewNonceManager(cfg *Config, addrs []common.Address, privKeys []*ecdsa.PrivateKey) (*NonceManager, error)

NewNonceManager creates a new nonce manager that tracks nonce for each address

func (*NonceManager) NextNonce

func (m *NonceManager) NextNonce(addr common.Address) *big.Int

NextNonce returns new nonce for addr this method is external for module testing, but you should not use it since handling nonces on the client is unpredictable

func (*NonceManager) UpdateNonces

func (m *NonceManager) UpdateNonces() error

UpdateNonces syncs nonces for addresses

type NonceManagerCfg

type NonceManagerCfg struct {
	KeySyncRateLimitSec int       `toml:"key_sync_rate_limit_per_sec"`
	KeySyncTimeout      *Duration `toml:"key_sync_timeout"`
	KeySyncRetries      uint      `toml:"key_sync_retries"`
	KeySyncRetryDelay   *Duration `toml:"key_sync_retry_delay"`
}

type NonceStatus added in v0.1.3

type NonceStatus struct {
	LastNonce    uint64
	PendingNonce uint64
}

type Pragma added in v1.0.10

type Pragma struct {
	Minor uint64
	Major uint64
	Patch uint64
}

Pragma represents the version of the Solidity compiler used to compile the contract

func DecodePragmaVersion added in v1.0.10

func DecodePragmaVersion(bytecode string) (Pragma, error)

DecodePragmaVersion extracts the pragma version from the bytecode or returns an error if it's not found or can't be decoded. Based on https://www.rareskills.io/post/solidity-metadata

func (Pragma) String added in v1.0.10

func (p Pragma) String() string

String returns the string representation of the Pragma

type TXCallTraceOutput

type TXCallTraceOutput struct {
	Call
	Calls []Call `json:"calls"`
}

func (*TXCallTraceOutput) AsCall

func (t *TXCallTraceOutput) AsCall() Call

type TXFourByteMetadataOutput

type TXFourByteMetadataOutput struct {
	CallSize int
	Times    int
}

type Trace

type Trace struct {
	TxHash       string
	FourByte     map[string]*TXFourByteMetadataOutput
	CallTrace    *TXCallTraceOutput
	OpCodesTrace map[string]interface{}
}

type TraceLog

type TraceLog struct {
	Address string   `json:"address"`
	Data    string   `json:"data"`
	Topics  []string `json:"topics"`
}

func (TraceLog) GetData

func (t TraceLog) GetData() []byte

func (TraceLog) GetTopics

func (t TraceLog) GetTopics() []common.Hash

type Tracer

type Tracer struct {
	Cfg *Config

	Addresses                []common.Address
	ContractStore            *ContractStore
	ContractAddressToNameMap ContractMap
	DecodedCalls             map[string][]*DecodedCall
	ABIFinder                *ABIFinder
	// contains filtered or unexported fields
}

func NewTracer

func NewTracer(url string, cs *ContractStore, abiFinder *ABIFinder, cfg *Config, contractAddressToNameMap ContractMap, addresses []common.Address) (*Tracer, error)

func (*Tracer) DecodeTrace

func (t *Tracer) DecodeTrace(l zerolog.Logger, trace Trace) ([]*DecodedCall, error)

DecodeTrace decodes the trace of a transaction including all subcalls. It returns a list of decoded calls. Depending on the config it also saves the decoded calls as JSON files.

func (*Tracer) PrintTXTrace

func (t *Tracer) PrintTXTrace(txHash string) error

func (*Tracer) SaveDecodedCallsAsJson

func (t *Tracer) SaveDecodedCallsAsJson(dirname string) error

func (*Tracer) TraceGethTX

func (t *Tracer) TraceGethTX(txHash string, revertErr error) error

type TransactOpt

type TransactOpt func(o *bind.TransactOpts)

TransactOpt is a wrapper for bind.TransactOpts

func WithGasFeeCap

func WithGasFeeCap(gasFeeCap *big.Int) TransactOpt

WithGasFeeCap sets gasFeeCap option for bind.TransactOpts

func WithGasLimit

func WithGasLimit(gasLimit uint64) TransactOpt

WithGasLimit sets gasLimit option for bind.TransactOpts

func WithGasPrice

func WithGasPrice(gasPrice *big.Int) TransactOpt

WithGasPrice sets gasPrice option for bind.TransactOpts

func WithGasTipCap

func WithGasTipCap(gasTipCap *big.Int) TransactOpt

WithGasTipCap sets gasTipCap option for bind.TransactOpts

func WithNoSend

func WithNoSend(noSend bool) TransactOpt

WithNoSend sets noSend option for bind.TransactOpts

func WithNonce

func WithNonce(nonce *big.Int) TransactOpt

WithNonce sets nonce option for bind.TransactOpts

func WithValue

func WithValue(value *big.Int) TransactOpt

WithValue sets value option for bind.TransactOpts

type TransactionLog

type TransactionLog struct {
	Topics []common.Hash
	Data   []byte
}

func (TransactionLog) GetData

func (t TransactionLog) GetData() []byte

func (TransactionLog) GetTopics

func (t TransactionLog) GetTopics() []common.Hash

Directories

Path Synopsis
cmd
contracts

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL