- Change
launch_anvil()
to use latest hardfork by default instead oflondon
- Add:
wait_and_broadcast_multiple_nodes_mev_blocker()
for MEV Blocker - because the tx broadcast must be sequential
- Add: TokenSniffer API wrapper with a persistent cache
- Add: Enzyme vault deployments on Arbitrum
- Add: Custom cache interface support for
CachedTokenSniffer()
- Add: dRPC
x-drpc-provider-id
header support for troubleshooting issues with decentralised node providers - Fixed: Whitelist HTTP 403 Forbidden for dRPC as a retryable error
- Add:
wait_and_broadcast_multiple_nodes(inter_node_delay)
to fix Alchemy ethereum/go-ethereum#26890 - Internal change: Move
deploy_guard()
to its own function and refactor Enzyme vault deployment to more manageable - Dependencies: Numpy < 2.x for now as it breaks too much stuff, updating dependencies is a headache
- Add and fixed: Various logging and diagnostics lines
- Fixed: Uniswap Subgraphs now require an API key
- Update Aave deploymenet list
- Add Aave v2 event reader support
- Handle HTTP 410 retryable, as returned by dRPC
- Make it possible to deploy in-house contracts without installing Enzyme toolchain: node.js, hardhat and node-gyp were un-co-operative. Instead, now we just flatten out Enzyme sol files and store them in the source tree as copies.
- Improved error messages for
GuardV0
- Handle HTTP 520 retryable, as returned by Alchemy JSON-RPC
- Handle
ValueError: {'code': -32000, 'message': 'execution aborted (timeout = 5s)'}
as returned by Alchemy RPC
- Improve graphql support check in
has_graphql_support()
- Handle HTTP 525 retryable, as returned by Alchemy JSON-RPC
- Add:
VaultPolicyConfiguration.shares_action_timelock
Have a safe redemption time lock on Enzyme vault deployments - Add: header not found in retryable exceptions
- Bump web3.py to 6.12.x
- Add Foundry and Forge integration:
deploy_contract_with_forge()
- Add initial Etherscan integration
- Add Terms of Service acceptance manager integration
- Add GuardV0 and SimpleVaultV0 implementations for creating safe automated asset managers
- Add support for Enzyme policies
- Added GuardV0 support for Enzyme vaults and generic adapters
- Add
get_native_token_price_with_chainlink()
to easily convert native token prices to USD\ - Add 1delta price estimation helper
OneDeltaPriceHelper
- Add
fetch-all-vaults.py
export all Enzyme vaults from the chain to a CSV file - Add
deploy_generic_adapter_vault
for correctly configured policy and safe vault deployment - Add Enzyme vault deployment tutorial
- Improve logging in
wait_and_broadcast_multiple_nodes
for post-mortem analysis hash(SignedTransactionWithNonce)
now isSignedTransactionWithNonce.hash
, Ethereum transaction hash- Improve various utility functions
- Fix issues cleaning AST information from Enzyme contracts on certain UNIX shells
- Fix log message in the fallback provider that if we have only a single provider don't call error handling "switching"
- Fix Sphinx dependencies to be dev dependencies
- Fix: invalid None check for sign_bound_call_with_new_nonce"
- Fix: Python pinning to 3.12.x
- Fix:
HotWallet.sign_bound_call_with_new_nonce
tries to avoid calling broken Web3 gas estimation machine if the gas parameters are already given as the arguments - Fix: Raise
OutOfGasFunds
in_broadcast_multiple_nodes
and avoid transaction broadcast retry if we do not have gas money - Fix: Don't swallow nonce errors and chain id errors in
broadcast_multiple_nodes
- Fix type normalisation of
tx_hash
infetch_transaction_revert_reason
- Figure out how to tackle Anvil unreliability issues
- Mark
evm_mine
JSON-RPC method not retryable - Fix
anvil.mine()
without parameters do not attempt to guess next block timestamp, as this was wrong under a load, probably due to Anvil's internal race conditions - Add
is_retryable_http_exception(method, params)
to allow decide the retry of a JSON-RPC request based on its inputs, not just the output exception - Add
eth_defi.timestamp.get_latest_block_timestamp()
- Add
eth_defi.timestamp.get_block_timestamp()
- Change 1delta
close_short_position()
API to be able to be able to specify the amount of collateral to withdraw
- Add
is_anvil(web3)
method - Add
fetch_erc20_balances_by_token_list(decimalise=True)
to get multiple token balances with decimal conversaion as a batch operation - Fix:
set_block_tip_latency()
defauts to 0 when connected tocreate_multi_provider_web3
to simplify testing - Remove LlamaNodes from Github CI configuration as was causing too much maintenance work and random failures
- Unpin some dependencies to make package installation easier
- Debian Bullseye and pyenv was picking up old web3-ethereum-defi version
- Create a Docker script to check installation on Debian Bullseye
- This did not then use the correct version of safe-pysha3, but picked up the old pysha3 package
- Make
pyproject.toml
to say we are compatible all they way to Python 3.12 - pkgutil compatibility fixes.
- Upgrade to Pandas 2.x, needed for Python 3.12 compatibility
- Upgrade to the latest Web3.py 6.x version
- Python 3.12 changes
ast
module and this has breaking changes witheth_trace
library. Workaround them. - Disable
test_fallback_double_fault
because new Web3.py does not likeMagicMock
results - Bump to
zope.dottedname
6.0 needed for Python 3.11 compatibility
- Fix installation error on Debian Bullseye and Python 3.11:
fatal error: pystrhex.h: No such file or directory
- Bump compatibility all the way up to Python 3.12
- Feature: Add 1delta integration position handlers
- Various improvements when working with low quality JSON-RPC nodes
- Uniswap v3 price tutorial is now runnable with low quality nodes
- API chance:
fetch_erc20_details(cache)
has now an internal cache, implemented with Python's cachetools package. - Add:
static_call_cache_middleware
to reduce the amount ofeth_chainId
API calls - Add:
TrackedLazyTimestampReader
to help working with slow nodes - Add:
MultiProviderWeb3.get_api_call_counts
to see JSON-RPC API call stats across all providers - Fix:
swap_with_slippage_protection(max_slippage)
is BPS - API change:
swap_with_slippage_protection(max_slippage=15)
- change the default Uniswap v3 trade slippage tolerance from (unrealistic) 0.1 BPS to 15 BPS. - Fix: The madness of JSON-RPC providers abuse the error code
-32000
. We check for error message now instead of error code. - Internal change: When reading events, only notify progress bar when we have an event hit,
to avoid unnecessary
eth_getBlockByNumber
calls for timestamps.
- API change: Handle
wait_and_broadcast_multiple_nodes()
so that it will attempt to retry multiple providers multiple times before raising the last exception
- Add
launch_anvil(fork_block_number)
option to create mainnet works on a specific block number. Naturally works only with archive nodes. - API change: If all providers fail in
wait_and_broadcast_multiple_nodes()
, raise the exception from the last provider.
- More retryable JSON-RPC errors whitelisted. Now
ValueError: {'code': -32701, 'message': 'Please specify address in your request or, to remove restrictions, order a dedicated full node here: https://www.allnodes.com/bnb/host'}
.
- More retryable JSON-RPC errors whitelisted. Now
{'code': -32005, 'message': 'limit exceeded'}
.
- Add
eth_defi.confirmation.check_nonce_mismatch
to verify our signed transactions have good nonces based on on-chain data - Add
wait_and_broadcast_multiple_nodes(check_nonce_validity)
and by default try to figure nonce issues before attemping to broadcast transactions
- Internal change: Increased logging for transaction broadcast issues
- Internal change: more aggressive change reading nodes in multi-node tx broadcast
- Internal change: more verbose logging for
wait_and_broadcast_multiple_nodes
- API change: add
fetch_erc20_balances_by_token_list(block_identifier)
- Add:
wait_and_broadcast_multiple_nodes
to work around transaction broadcasts and confirmations failing on LlamaNodes - Fix: First workaround for
JSON-RPC error: {'code': -32003, 'message': 'max priority fee per gas higher than max fee per gas'}
ineth_defi.gas
- Don't pin down
pyarrow
version to make it easier to use different Arrow reading backends
- Add
eth_defi.provider.broken_provider.get_almost_latest_block_number()
for developer ergonomics when working with Ankr and LlamaNodes - If using
FallbackProvider
switch node providers inwait_transactions_to_complete
because Ankr and LlamaNodes low service quality issues
- Work around
web3.exceptions.BlockNotFound
with LlamaNodes.com
- Added
ChunkedEncodingError
to automatically retryable errors. This error happens on LlamaNodes.com and is likely a quality of a service issue on their behalf.
- Make testing and
launch_anvil
distrubuted safe by randomising Anvil localhost port it binds. Test now run in few minutes instead of tens of minutes. Tests must be still run withpytest --dist loadscope
as individual test modules are not parallel safe. - Add
eth_defi.broken_provider.set_block_tip_latency()
to control the default delays for which we expect the chain tip to stabilise.
- Work around
BadFunctionCallOutput
: Insufficient bytes exception: A special case of eth_call returning an empty result. This happens if you call a smart contract for a block number for which the node does not yet have data or is still processing data. This happens often on low-quality RPC providers (Ankr) that route your call between different nodes between subsequent calls, and those nodes see a different state of EVM. Down the line, not in the middleware stack, this would lead toBadFunctionCallOutput
output. We work around this by detecting this condition in the middleware stack and triggering the middleware fall-over node switch if the condition is detected. - Set
FallbackProvider
to have the default4
blocks latency for alllatest
calls, inget_default_block_tip_latency()
so that fail over switches are more robust.
- Fix FallbackProvider to work with certain problematic error codes
- Log non-retryable exceptions in fallback middleware, so there is better diagnostics why fallback fails
- Add
HotWallet.fill_in_gas_estimations()
- Add
{'code': -32043, 'message': 'Requested data is not available'}
to RPC exceptions where we assume it's an error we can either resume or switch to the next node provider. This error was encoureted witheth_getLogs
when using LlamaNodes.
- Allow passing
request_kwargs
to create_multi_provider_web3 - When setting up TunedWeb3Factory use
create_multi_provider_web3
to set up the connections instead pooled threads and processed - Switch to ujson for JSON-RPC decoding by default with
create_multi_provider_web3
- Fix
test_block_reader
tests
- Retry nonce too low errors, (related to LLamaNodes).
- Add
eth_defi.provider.llamanodes
and work around issues with LlamaNodes.com
- Move Ankr specific functionality to its own
eth_defi.provider.ankr
module that will see more changes in the future
- Add
eth_defi.rpc.broken_provider
for workaround for the quirks and features of different JSON-RPC providers - Ankr workaround for
BlockNotFound
exception.
- Add: Aave v3 reserve data queries
- Add: More logging to
swap_with_slippage_tolerance
for Uniswap v3 to diagnose failed trades
- Fix: Decimal place adjustment when calculating Uniswap v3 fees
- Fix: Aave v3 event reader dealing with different block number formats from JSON-RPC nodes
- Add: Uniswap v3 LP fees are now accounted in the trade analysis
- Fix: Documentation now generates proper title and description HTML meta tags for automatically generated API documentation
- JSON-RPC fallback and MEV protection tutorial
- Added missing
sigfig
lib dependency
- Fix:
eth_defi.chain.has_graphql_support
to supportMultiProviderWeb3
- Add:
eth_defi.provider.multi_provider.create_multi_provider_web3
: An easy way to configure a Web3 instance with multiple providers
- Add logging to
swap_with_slippage_protection()
on Uniswap v3 to trace slippage issues
- Refactor a lot of functionality to a new submodule eth_defi.provider
- Add MEV blocking support in the form of
eth_defi.mev_blocker.MEVBlockerProvider
- Add JSON-RPC fallback switching in the form of
eth_defi.fallback_provider.FallbackProvider
- Add
HotWallet.create_for_testing
- Add utility function
get_onchain_price()
to ask on-chain price of a Uniswap v3 pool at any given block number - Add
eth_defi.event_reader.logresult.decode_log
and better documentation forLogResult
class - Deprecate
eth_defi.anvil
->eth_defi.provider.anvil
- Deprecate
eth_defi.ganache
->eth_defi.provider.ganache
- Add test coverage for
extract_timestamps_json_rpc_lazy
- Expose API call counter in
LazyTimestampContainer
- Add
block_identifier
parameteter toestimate_buy_received_amount() / estimate_sell_received_amount()
, so we can ask historical prices and also track the price information per block - Fix
0x
hash prefix missing inLazyTimestampContainer
- looks like live RPC nodes
where returning JSON-RPC responses differently formatted
- Add
HotWallet.sign_bound_call_with_new_nonce
- Create
extract_timestamps_json_rpc_lazy
that instead of reading block timestamps upfront for the given range, only calls JSON-RPC API when requested. It works on the cases where sparse event data is read over long block range and it is likely only few timestamps need to be fetched in this range.
- Added
eth_defi.enzyme.erc_20
helpers
- Fix error message
fetch_transaction_revert_reason()
crashing. Also made the error message prettier and more helpful.
- Add
AssetDelta.__mul__
method
- Attempt to fix packaging to workaround the new PyPi ZIP bomb check. Enzyme ABI files no longer include AST data.
- Add
fetch_vault_balances()
state reading balance support for Enzyme vaults.
- Add EIP-3009
transferWithAuthorization
support. Related refactoring of EIP-3009 module.
- Fix: Token equality:
TokenDetails
does a logical comparison with chain id and address, instaed of object comparison. This makes TokenDetails good for ifs and hash maps. This addsTokenDetails.__eq__
andTokenDetails.__hash__
. - Fix
TradeSuccess.price
is in PythonDecimal
- Add:
TradeSucces.get_human_price(reverse_token_order: bool)
- Add USDC (Centre FiatToken)
- Add EIP-712
- Add EIP-3009
- Add
transferWithAuthorization
andreceivedWithAuthorization
- Add Enzyme vault USDC payment forwarder allowing single click purchases (no
approve
step) - Fix: Don't try to
trace_transaction
unless we know we are on Anvil - Add Aave v3 loan support in
eth_defi.aave_v3.loan
module
- Add: Enzyme's FundValueCalculator contract as part of the deployment
- Fix: Excessive log output if
__repr__
on GraphQLReorganisationMonitor - Fix: Aave deployer tests fail on Github
- Add Aave v3 deployer support in
eth_defi.aave_v3.deployer
module - Add Solidity library linking support for Hardhat-based deployments in
eth_defi.abi.get_linked_contract
- Add: More logging and better error messages to some parts
- Add:
figure_reorganisation_and_new_blocks(max_range)
to catch situations you somehow feed a too long block range to scan - Add:
analyse_trade_by_receipt(input_args)
to analyse the success of Uni v3 trades when trading on Enzyme
- Fix: Use
web3.eth.wait_for_transaction_receipt
in appropriate places - Add: Helper functions to interact with
UniswapV3PriceHelper
- Add: TQDM progress bar support for event reading in the form
of
eth_defi.event_reader.progress_update.TQDMProgressUpdate
- Add: Enzyme price feed removal support
- Add:
eth_defi.chain.fetch_block_timestamp
shortcut method - Fix: Web3 6.0 compatibility
- Fix: Better error message when reorganisation monitor is missing blocks
- Fix:
EnzymePriceFeed.primitive_token
resolution fails on some Enzyme tokens on Polygon
- Add argument
Vault.fetch(generic_adapter_address)
- Fix: Handle
HexBytes
event signatures for Web3 6.0 - API change: No longer allow
HexBytes
results to fall through inLogResult
to make sure all event readers get the data in the same format
- Dependency version updates
- Fix: Various fixes to transaction receipt handling
- Fix: Report the revert reason why Uniswap v2 pair deployment fails
- Fix:
eth_defi.uniswap_v2.analysis.analyse_trade_by_receipt
supports complex compounded transactions - Add:
eth_defi.deploy.get_registered_contract
for unit test contract diagnosis - API change:
VaultControllerWallet.sign_transaction_with_new_nonce
has new API - API change: Use bound
ContractFunction
inEnzymeVaultTransaction
- Reorganise ABI compilation process, source dependencies and
eth_defi.abi
folder layout - In-house contracts are now compiled using Foundry
- Add
VaultSpecificGenericAdapter.sol
for Enzyme - Add
eth_defi.enzyme.vault_controlled_vallet
- Add
eth_defi.tx.AssetDelta
- Add
Vault.fetch_denomination_token_usd_exchange_rate
- Add initial Chainlink support
Add eth_defi.reader.multithread.MultithreadEventReader for easy to use high-speed Solidity event reading
- Add Enzyme's price feeds
- Add Enzyme's
Vault.fetch
- Add
eth_defi.utils.to_unix_timestamp
- Add
eth_defi.reorganisation_monitor.create_reorganisation_monitor
- Rename:
eth_defi.enzyme.events.Withdrawal
->Redemption
- Optimize
get_contract
with improved caching - Add preliminary
assert_call_success_with_explanation
- but looks like Anvil support is still missing, so currently hacked together
- Add
EnzymeDeployment.fetch_vault
- Add
Vault.fetch_deployment_event
- Add
BroadcastFailure
exception - Fix token sorting condition in Uniswap v2 pair deployment
- Fix Anvil launch to do three attempts by default if the process fails to launch
- Web3.py 6.0 release API fixes
- Add API call count middleware
- Fix: Clean accidentally released breakpoint code in revert middleware
Added a script for verifying the integrity of your EVM JSON-RPC node data
- Added
TunedWeb3Factory(thread_local_cache)
option for more performant web3 connection when using thread pooling
- Migrate to Web3.py 6.0. Notable Web3.py API changes:
toChecksumAddress
->to_checksum_address
processReceipt
->process_receipt
web3.contract.Contract
->web3.contract.contract.Contract
solidityKeccak
->solidity_keccak
decode_function_input
returns dict instead of tuple
- Support Anvil as the unit test backend ove
EthereumTester
- Anvil is much faster deploy_contract()
tracks deployed contracts and their ABIs so we can print symbolic Solidity stack traces- Print Solidity stack traces of failed transactions using
print_symbolic_trace()
andtrace_evm_transaction()
- Adding initial Enzyme Protocol APIs
- Adding dHEDGE Protocol ABI files and compile commands
- Add
revert_reason_middleware
- Documentation restructure
- Add Ethereum to
AAVE_V3_NETWORKS
configuration - Fix price calculation in Uniswap v3
analysis.py
- Replace
ganache
withanvil
as the mainnet fork solution. Anvil is much more stable than Ganache what comes to JSON-RPC. Anvil is much faster. You can now call fork_network_anvil that is a drop-in replacement for old Ganache basedfork_network
. - Move internal test suite to use Anvil instead of Ganache. This allows us to remove
flaky
decorators on tests. - Add
analysis.py
for Uniswap V3 and relevant tests - Add
mock_partial_deployment
function for V3 - Abstract
TradeResult
,TradeSuccess
, andTradeFailure
out of Uniswap V2 and into eth_defi.trade, since also used in Uniswap V3 - Add Uniswap V3
increase_liquidity()
anddecrease_liquidity()
by @pbharrin
- Add Uniswap V3 decode_path method
- Uniswap v3 fixes
- Add middleware support for Avalanche C-chain
- Fix retry sleep not reset between function calls in
exception_retry_middleware
- Fix
extract_timestamps_json_rpc
to be compatible with both middlewared and non-middlewared JSON-RPC request format (string hex numbers vs. converted ints).
- Attempt to overcome
ValueError: {'message': 'Internal JSON-RPC error.', 'code': -32603}
if served by a Pokt relay
has_graphql_support
made more robust
- Retry middleware fine tuning
- Off by one fix in read_events_concurrent max block range
- More event reader test coverage
- Better test and exception coverage if bad
extract_timestamps
is passed while reading events. This prevents the library user to write a bad timestamp provider function.
- Fix
filter
andevent
assert inread_events_concurrent()
- Fix: Duplicate events appearing when using the concurrent event reader
- Added
ReorganisationMonitor
andChainReorganisationDetected
to deal with unstable chain tips when doing event ignestion - Added
uniswap-v2-pairs-swap-live.py
example that shows real-time swaps happening on QuickSwap (Polygon) in a terminal - Add
has_graphql_support()
to detect GraphQL interface on GoEthereum - Add
GraphQLReorganisationMonitor
for very fast downloading of block headers and timestamps using GoEthereum /graphql API
- Added
generate_fake_uniswap_v2_data()
to generate synthetic Uniswap v2 trade feeds - Improved
PairDetails
API, addedget_current_mid_price()
- Add
PairDetails.checksum_free_address
to shortcut getting lowercased Ethereum address - Added
convert_jsonrpc_value_to_int()
to deal differences between real JSON-RPC and EthereumTester - Add
install_chain_middleware()
andinstall_retry_middleware()
- Add
measure_block_time()
- Add multiple contract address filtering to the event reader
- Add
fetch_deployment
for Uniswap v3 - Add
swap_with_slippage_protection
for Uniswap v3
- Add new PriceOracle types for unit testing
- Adding Trader Joe compatibility. Unlike other clones, Trader Joe uses
Router.WAVAX
insteadRoueter.WETH
for the native token variable. - Document BNB Chain "Limits exceeded" error - BNB Chain eth_getLogs have been disabled on public endpoints
- Moving
nbsphinx
to optional dependency, was as core dependency by accident
- Feature: generic price oracle implementation with configurable price function
- Feature: time weighted average price (TWAP) price function for price oracle
- Feature: price oracle implementation for Uniswap v2 and v3 pools
- Feature:
update_live_price_feed
for real-time Uniswap v2 and v3 price oracles - Feature:
fetch_pair_details
to get info on Uniswap v2 pairs - API change: Refactored event filter implementation to
eth_defi.reader.filter
- Fix: Python 3.9 or later required
- Feature: Added Uniswap V3 price helper (both single hop and multi hops)
- API change: Moved Uniswap V3
add_liquidity
to its own function - Fix: Correct slippage calculation to match official Uniswap v2 SDK
- Fix: Microsoft Windows compatibility: Always use utf-8 when reading and writing text files
Feature: JSON-RPC retry middleware with sleep and backoff
- Feature: Added decode_signed_transaction with EIP-2718 and EIP-2930 tx support
- Feature: Added
estimate_buy_received_amount_raw
andestimate_sell_received_amount_raw
- Fix: pairFor could give a wrong address for trading pair
- Fix: Cosmetic API improvements and fixes, with more asserts
- API change: Split
analyse_trade
->analyse_trade_by_hash
andanalyse_trade_by_receipt
- API change: Rename module
txmonitor
->confirmation
- Update web3.py dependency to 5.28.0
- Feature: Added Uniswap v2 swap function with slippage protection
- Feature: Added support for
fee
andslippage
to Uniswap v2 price calculations - Feature: Added Uniswap v2 pair liquidity fetch
- Feature: Added support for three-way swap (swap through an intermediate token) and price calculations
- Feature: Added support for transfer fee, token tax and honeypot checks
- API change: Moved
get_amount_in
andget_amount_out
toUniswapV2FeeCalculator
class - Fix: Improve exception message when transactions timeout
- Feature: Added ERC-20 transfer tutorial
- Completed migration to new web3-ethereum-defi package name
- Feature: Added revert reason extraction for failed transactions
- Feature: Added
eth_defi.gas.node_default_gas_price_strategy
to support BNB Chain - Fix: BNB Chain compatibility fixes because of brokeness in Ethereum JSON-RPC
- Fix: Ganache compatibility fixes because of brokeness in Ethereum JSON-RPC
- Fix: Wait 10 seconds instead of 5 seconds to ganache-cli to launch, as the latter is too slow for some computers
- Fix: Optimize
wait_transactions_to_complete
- API change: Created a separate
broadcast_transactions
function
- Feature: Added initial Uniswap v3 testing support
- Feature: Allow override init code hash for
eth_defi.uniswap_v2.fetch_deployment
- Feature: Faster failing if ganache-cli RPS port is already taken
- Feature: Added
fetch_erc20_balances_by_token_list
- Feature: Added
get_transaction_data_field
- API change:
uniswap_v2
oruniswap_v3
are now their respective submodules - API change: Rename
fetch_erc20_balances
->fetch_erc20_balances_by_transfer_event
- API change: Removed
fetch_erc20_balances_decimal_by_transfer_event
- API change: Rename
convert_to_decimal
->convert_balances_to_decimal
- Fix:
fetch_erc20_balances
: User friendly error message when trying to grab a too big chunk of transfers once - Fix: Use
london
hard fork by default forfork_network
Feature: eth_defi.ganache module to support ganache-cli mainnet forks
- Feature:
HotWallet.get_native_currency_balance
to easier management of hot wallet accounts - Feature:
HotWallet.from_private_key
to easier management of hot wallet accounts
- Rename module:
eth_defi.portfolio
->eth_defi.balances
- Fix: Documentation now builds correctly with body text for functions
- Fix: ERC-20 balances when there exist debit transactions
- Feature: ERC-20 token deployments with custom decimals
- Feature: Wallet ERC-20 token holdings analysis
- Feature: Scaleable Solidity event fetcher
- Feature: Uniswap v2 price impact and fee estimator
- Feature: Fetch Uniswap deployment from on-chain data
- Feature: ERC-20 detail fetcher
- Feature: London hard fork compatible gas estimator
- Feature: Hot wallet with nonce management and batch sending
- Feature: Sending and confirming transactions in batches
- Renamed package to
eth-hentai
- Initial release