NetAssetValueCalculator

Documentation for eth_defi.vault.valuation.NetAssetValueCalculator Python class.

class NetAssetValueCalculator[source]

Calculate valuation of all vault spot assets, assuming we would sell them on Uniswap market sell or similar.

  • Query valuations using only onchain data / direct quoter smart contracts, no external indexers or services needed

  • Price impact and fees included

  • Brute forces all possible route combinations

  • Pack more RPC punch by using Multicall library

Note

Early prototype code.

Example:

vault = lagoon_vault

universe = TradingUniverse(
    spot_token_addresses={
        base_weth.address,
        base_usdc.address,
        base_dino.address,
    }
)
latest_block = get_almost_latest_block_number(web3)
portfolio = vault.fetch_portfolio(universe, latest_block)
assert portfolio.get_position_count() == 3

uniswap_v2_quoter_v2 = UniswapV2Router02Quoter(uniswap_v2.router)

nav_calculator = NetAssetValueCalculator(
    web3,
    denomination_token=base_usdc,
    intermediary_tokens={base_weth.address},  # Allow DINO->WETH->USDC
    quoters={uniswap_v2_quoter_v2},
    debug=True,
)

routes = nav_calculator.create_route_diagnostics(portfolio)

print(routes)

Outputs:

# Routes and their sell values:

                      Asset                                     Address        Balance                   Router Works  Value
 Path
 USDC                  USDC  0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913           0.35                            yes   0.35
 WETH -> USDC          WETH  0x4200000000000000000000000000000000000006       0.000000  UniswapV2Router02Quoter   yes   0.00
 DINO -> USDC          DINO  0x85E90a5430AF45776548ADB82eE4cD9E33B08077  547942.000069  UniswapV2Router02Quoter    no      -
 DINO -> WETH -> USDC  DINO  0x85E90a5430AF45776548ADB82eE4cD9E33B08077  547942.000069  UniswapV2Router02Quoter   yes  36.69

Methods summary

__init__(web3, denomination_token, ...[, ...])

Create a new NAV calculator.

calculate_market_sell_nav(portfolio[, ...])

Calculate net asset value for each position.

create_route_diagnostics(portfolio)

Create a route diagnotics table.

do_multicall(calls)

Multicall mess untangling.

fetch_onchain_valuations(routes, portfolio)

Use multicall to make calls to all of our quoters.

find_swap_routes(portfolio[, buy])

Find the best routes to buy tokens.

generate_routes_for_router(router, portfolio)

Create all potential routes we need to test to get quotes for a single asset.

resolve_best_valuations(input_tokens, routes)

Any source token may have multiple paths.

try_swap_paths(routes, portfolio)

Use multicall to try all possible swap paths for tokens.

__init__(web3, denomination_token, intermediary_tokens, quoters, multicall=None, block_identifier=None, multicall_gas_limit=10000000, debug=False, batch_size=15, legacy_multicall=False)[source]

Create a new NAV calculator.

Parameters
  • denomination_token (Union[eth_typing.evm.HexAddress, eth_defi.token.TokenDetails]) –

    Value the portfolio in this token.

    E.g. USDC

  • intermediary_tokens (set[Union[eth_typing.evm.HexAddress, eth_defi.token.TokenDetails]]) –

    When looking for sell routes, these are allowed tokens we can do three leg trades.

    E.g. WETH, USDT.

  • quoters (set[eth_defi.vault.valuation.ValuationQuoter]) – Supported DEX quoters we can sell on.

  • block_identifier (Optional[Union[Literal['latest', 'earliest', 'pending', 'safe', 'finalized'], eth_typing.evm.BlockNumber, eth_typing.evm.Hash32, eth_typing.encoding.HexStr, int]]) – Block number for the valuation time.

  • multicall (Optional[bool]) –

    Use multicall to optimise RPC access.

    None = autodetect.

    True = force.

    False = disabled.

  • multicall_gas_limit – Let’s not explode our RPC node

  • batch_size – Batch size to one Multicall RPC in the number of calls.

  • debug

    Unit test flag.

    Print out failed calldata to logging INFO, so you can inspect failed multicalls in Tenderly debugger.

  • web3 (web3.main.Web3) –

generate_routes_for_router(router, portfolio, buy=False)[source]

Create all potential routes we need to test to get quotes for a single asset.

Parameters
Return type

Iterable[eth_defi.vault.valuation.Route]

calculate_market_sell_nav(portfolio, allow_failed_routing=False)[source]

Calculate net asset value for each position.

  • Portfolio net asset value is the sum of positions

  • What is our NAV if we do market sell on DEXes for the whole portfolio now

  • Price impact included

param allow_failed_routing

Raise an error if we cannot get a single route for some token

s
return

Map of token address -> valuation in denomiation token

Parameters

portfolio (eth_defi.vault.base.VaultPortfolio) –

Return type

eth_defi.vault.valuation.PortfolioValuation

resolve_best_valuations(input_tokens, routes)[source]

Any source token may have multiple paths. Pick one that gives the best amount out.

Parameters
do_multicall(calls)[source]

Multicall mess untangling.

Parameters

calls (list[eth_defi.event_reader.multicall_batcher.MulticallWrapper]) –

fetch_onchain_valuations(routes, portfolio, legacy=False)[source]

Use multicall to make calls to all of our quoters.

  • Does not handle reserve currency, as this never has any route to itself

Returns

Map routes -> amount out token amounts with this route

Parameters
Return type

dict[eth_defi.vault.valuation.Route, decimal.Decimal]

try_swap_paths(routes, portfolio)[source]

Use multicall to try all possible swap paths for tokens.

  • Find the best buy options

  • Assume VaultPortfolio.spot_erc20 contains token amounts we want to buy

Returns

Map routes -> amount out token amounts with this route

Parameters
Return type

dict[eth_defi.vault.valuation.Route, decimal.Decimal]

create_route_diagnostics(portfolio)[source]

Create a route diagnotics table.

  • Show all routes generated for the portfolio

  • Flag routes that work

  • Show values of each portfolio position if sold with the route

Outputs:

                     Asset                                     Address        Balance                   Router Works  Value
Path
USDC                  USDC  0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913           0.35                            yes   0.35
WETH -> USDC          WETH  0x4200000000000000000000000000000000000006       0.000000  UniswapV2Router02Quoter   yes   0.00
DINO -> USDC          DINO  0x85E90a5430AF45776548ADB82eE4cD9E33B08077  547942.000069  UniswapV2Router02Quoter    no      -
DINO -> WETH -> USDC  DINO  0x85E90a5430AF45776548ADB82eE4cD9E33B08077  547942.000069  UniswapV2Router02Quoter   yes  36.69
Returns

Human-readable DataFrame.

Indexed by asset.

Parameters

portfolio (eth_defi.vault.base.VaultPortfolio) –

Return type

pandas.core.frame.DataFrame

find_swap_routes(portfolio, buy=True)[source]

Find the best routes to buy tokens.

Parameters

portfolio (eth_defi.vault.base.VaultPortfolio) –

Return type

eth_defi.vault.valuation.SwapMatrix