Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save normanlmfung/d1fedb7600698735d89d7cbf7253bd71 to your computer and use it in GitHub Desktop.
Save normanlmfung/d1fedb7600698735d89d7cbf7253bd71 to your computer and use it in GitHub Desktop.
Fetch historical price of SINGLE/USDC from VVS/CRONOS
"""
This script gets the buy/sell prices from the vvs finance (https://vvs.finance/swap) smart contracts
for a given block number and path.
"""
from datetime import datetime
from dataclasses import dataclass
from typing import (
Dict,
List,
Literal,
Optional,
Union,
)
from web3 import Web3
from web3.types import (
ChecksumAddress
)
w3_cro = Web3(Web3.HTTPProvider("https://evm.cronos.org"))
vvs_router_abi = '[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]' # noqa
vvs_router_address = Web3.toChecksumAddress("0x145863Eb42Cf62847A6Ca784e6416C1682b1b2Ae")
vvs_contract = w3_cro.eth.contract(address=vvs_router_address, abi=vvs_router_abi)
@dataclass
class Token:
address: ChecksumAddress
symbol: str
decimals: int
def __init__(self, address: Union[str, ChecksumAddress], symbol: str, decimals: int) -> None:
self.address = Web3.toChecksumAddress(address)
self.symbol = symbol
self.decimals = decimals
def __eq__(self, other) -> bool:
if not isinstance(other, Token):
return False
return self.address == other.address
token_by_symbol: Dict[str, Token] = {
"USDC": Token("0xc21223249CA28397B4B6541dfFaEcC539BfF0c59", "USDC", 6),
"USDT": Token("0x66e428c3f67a68878562e79A0234c1F83c208770", "USDT", 6),
"SINGLE": Token("0x0804702a4E749d39A35FDe73d1DF0B1f1D6b8347", "SINGLE", 18),
}
def get_buy_price(
path_with_symbols: List[str],
block_number: Optional[int] = None,
quote_token_qty: float = 1000) -> float:
"""
This function computes the buy price given by the vvs finance smart contracts, providing no one front-run you, and including the exchange 0.3% fee # noqa
:param path_with_symbols: a list of 2 or 3 symbols, starting with the quote token. Ex ["USDC", "SINGLE"] or ["USDT", "USDC", "SINGLE"] # noqa
:param block_number: the block number at which we want the price. Default is None and gives the current price
:param quote_token_qty: The quantity of quote tokens used to get the price. Default to 1000.
:return: The buy price
"""
path = [token_by_symbol[symbol].address for symbol in path_with_symbols]
quote_token = token_by_symbol[path_with_symbols[0]]
base_token = token_by_symbol[path_with_symbols[-1]]
in_quantity = int(quote_token_qty * 10**quote_token.decimals)
block_identifier: Union[Literal['latest'], int] = block_number if block_number else 'latest'
out_quantity = vvs_contract.functions.getAmountsOut(in_quantity, path).call(block_identifier=block_identifier)[-1]
buy_price = quote_token_qty / (out_quantity / 10**base_token.decimals)
return buy_price
def get_sell_price(
path_with_symbols: List[str],
block_number: Optional[int] = None,
quote_token_qty: float = 1000) -> float:
"""
This function computes the sell price given by the vvs finance smart contracts, providing no one front-run you, and including the exchange 0.3% fee # noqa
:param path_with_symbols: a list of 2 or 3 symbols, ending with the quote token. Ex ["SINGLE", "USDC"] or ["SINGLE", "USDC", "USDT"] # noqa
:param block_number: the block number at which we want the price. Default is None and gives the current price
:param quote_token_qty: The quantity of quote tokens used to get the price. Default to 1000.
:return: The sell price
"""
path = [token_by_symbol[symbol].address for symbol in path_with_symbols]
quote_token = token_by_symbol[path_with_symbols[-1]]
base_token = token_by_symbol[path_with_symbols[0]]
out_quantity = int(quote_token_qty * 10 ** quote_token.decimals)
block_identifier: Union[Literal['latest'], int] = block_number if block_number else 'latest'
in_quantity = vvs_contract.functions.getAmountsIn(out_quantity, path).call(block_identifier=block_identifier)[0]
sell_price = quote_token_qty / (in_quantity / 10**base_token.decimals)
return sell_price
if __name__ == "__main__":
"""
Usage examples
"""
block_number = 2940370
sample_block = w3_cro.eth.get_block(block_number)
print(f"block#: {block_number}, {datetime.utcfromtimestamp(sample_block.timestamp)}")
print(get_buy_price(["USDC", "SINGLE"], block_number=block_number, quote_token_qty=10000))
block_number = 2940383
sample_block = w3_cro.eth.get_block(block_number)
print(f"block#: {block_number}, {datetime.utcfromtimestamp(sample_block.timestamp)}")
print(get_buy_price(["USDT", "USDC", "SINGLE"], block_number=block_number, quote_token_qty=10000))
block_number = 2940348
sample_block = w3_cro.eth.get_block(block_number)
print(f"block#: {block_number}, {datetime.utcfromtimestamp(sample_block.timestamp)}")
print(get_sell_price(["SINGLE", "USDC"], block_number=block_number, quote_token_qty=10000))
block_number = 2940395
sample_block = w3_cro.eth.get_block(block_number)
print(f"block#: {block_number}, {datetime.utcfromtimestamp(sample_block.timestamp)}")
print(get_sell_price(["SINGLE", "USDC", "USDT"], block_number=block_number, quote_token_qty=10000))
# Get latest
print(get_buy_price(["USDC", "SINGLE"])) # get the current buy price for the default amount (1000 USDC)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment