"""Vault share price estimator."""
import logging
import datetime
from decimal import Decimal
from typing import Optional
from eth_defi.erc_4626.estimate import estimate_4626_redeem, estimate_4626_deposit
from eth_defi.erc_4626.vault import ERC4626Vault
from web3 import Web3
from tradeexecutor.ethereum.vault.vault_routing import get_vault_for_pair
from tradeexecutor.state.identifier import TradingPairIdentifier
from tradeexecutor.state.types import USDollarAmount
from tradeexecutor.strategy.pricing_model import PricingModel
from tradeexecutor.strategy.trade_pricing import TradePricing
logger = logging.getLogger(__name__)
[docs]class VaultPricing(PricingModel):
"""Always pull the latest live share price of a vault.
.. note::
Only supports stablecoin-nominated vaults
"""
[docs] def __init__(
self,
web3: Web3,
):
self.web3 = web3
[docs] def get_vault(self, target_pair: TradingPairIdentifier) -> ERC4626Vault:
"""Helper function to speed up vault deployment resolution."""
return get_vault_for_pair(self.web3, target_pair)
[docs] def get_sell_price(
self,
ts: datetime.datetime,
pair: TradingPairIdentifier,
quantity: Optional[Decimal],
) -> TradePricing:
"""Get live price on vault for dumping our shares."""
assert pair.is_vault()
if quantity is None:
quantity = Decimal(self.very_small_amount)
assert isinstance(quantity, Decimal)
block_number = self.web3.eth.block_number
vault = self.get_vault(pair)
estimated_usd = estimate_4626_redeem(
vault=vault,
owner=None,
share_amount=quantity,
block_identifier=block_number,
)
price = float(quantity / estimated_usd)
mid_price = price
return TradePricing(
price=price,
mid_price=mid_price,
lp_fee=[0.0],
pair_fee=[0.0],
side=False,
path=[pair],
read_at=datetime.datetime.utcnow(),
block_number=block_number,
token_in=quantity,
token_out=estimated_usd,
)
[docs] def get_buy_price(
self,
ts: datetime.datetime,
pair: TradingPairIdentifier,
reserve: Optional[Decimal],
) -> TradePricing:
"""Get live price on vault for dumping our shares."""
assert pair.is_vault()
assert isinstance(reserve, Decimal)
block_number = self.web3.eth.block_number
vault = self.get_vault(pair)
estimated_shares = estimate_4626_deposit(
vault=vault,
denomination_token_amount=reserve,
block_identifier=block_number,
)
price = float(estimated_shares / reserve)
mid_price = price
return TradePricing(
price=price,
mid_price=mid_price,
lp_fee=[0.0],
pair_fee=[0.0],
side=False,
path=[pair],
read_at=datetime.datetime.utcnow(),
block_number=block_number,
token_in=reserve,
token_out=estimated_shares,
)
[docs] def get_mid_price(
self,
ts: datetime.datetime,
pair: TradingPairIdentifier
) -> USDollarAmount:
return self.get_buy_price(ts, pair, Decimal(1))
[docs] def get_pair_fee(
self,
ts: datetime.datetime,
pair: TradingPairIdentifier,
) -> Optional[float]:
return 0.0