我正在使用Web3.py,我遇到了一些奇怪的事情。
对于以下代码(使用煎饼路由器V2(:
from web3 import Web3
from web3.middleware import geth_poa_middleware
web3 = Web3(Web3.HTTPProvider('https://bsc-dataseed1.binance.org:443'))
web3.middleware_onion.inject(geth_poa_middleware, layer=0)
ABI = {"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"}
CAKE_ROUTER_V2 = web3.toChecksumAddress('0x10ed43c718714eb63d5aa57b78b54704e256024e')
router_contract = web3.eth.contract(address=CAKE_ROUTER_V2, abi=ABI),
WBNB = web3.toChecksumAddress('0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c')
CAKE = web3.toChecksumAddress('0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82')
KONGSHIBA = web3.toChecksumAddress('0x126f5f2a88451d24544f79d11f869116351d46e1')
print(router_contract.functions.getAmountsOut(1, [WBNB, CAKE]).call())
print(router_contract.functions.getAmountsOut(1, [WBNB, KONGSHIBA]).call())
我得到了以下信息:
[1, 19]
[1, 160]
WBNB和CAKE有18位小数,KONGSHIBA有17位。
虽然CAKE的价值目前约为27.7美元,WBNB为545.41291093美元
,KONGHIBA为0.000000000000000000000332美元。
所以我应该回去:
[1, 19]
[1, 16000000000000000000]
请告知。
计算代币价格的正确方法是询问流动性池(该代币与本地PEG或某些美元代币的配对(插入的PEG与代币数量的比率(有关流动性池代表什么的更多详细信息,请参阅https://uniswap.org/docs/v2/core-concepts/pools/)。
因此,对于python的使用:
from web3 import Web3
from web3.middleware import geth_poa_middleware # Needed for Binance
from json import loads
from decimal import Decimal
ETHER = 10 ** 18
WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
CAKE_ROUTER_V2 = web3.toChecksumAddress('0x10ed43c718714eb63d5aa57b78b54704e256024e')
web3 = Web3(Web3.HTTPProvider('https://bsc-dataseed1.binance.org:443'))
web3.middleware_onion.inject(geth_poa_middleware, layer=0) # Again, this is needed for Binance, not Ethirium
ABI = loads('[{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"}]')
def get_price(token, decimals, pair_contract, is_reversed, is_price_in_peg):
peg_reserve = 0
token_reserve = 0
(reserve0, reserve1, blockTimestampLast) = pair_contract.functions.getReserves().call()
if is_reversed:
peg_reserve = reserve0
token_reserve = reserve1
else:
peg_reserve = reserve1
token_reserve = reserve0
if token_reserve and peg_reserve:
if is_price_in_peg:
# CALCULATE PRICE BY TOKEN PER PEG
price = (Decimal(token_reserve) / 10 ** decimals) / (Decimal(peg_reserve) / ETHER)
else:
# CALCULATE PRICE BY PEG PER TOKEN
price = (Decimal(peg_reserve) / ETHER) / (Decimal(token_reserve) / 10 ** decimals)
return price
return Decimal('0')
if __name__ == '__main__':
CAKE_FACTORY_V2 = web3.eth.contract(address=CAKE_ROUTER_V2, abi=ABI).functions.factory().call()
token = web3.toChecksumAddress('0x126f5f2a88451d24544f79d11f869116351d46e1')
pair = web3.eth.contract(address=CAKE_FACTORY_V2, abi=ABI).functions.getPair(token, WBNB).call()
pair_contract = web3.eth.contract(address=pair, abi=ABI)
is_reversed = pair_contract.functions.token0().call() == WBNB
decimals = web3.eth.contract(address=token, abi=ABI).functions.decimals().call()
is_price_in_peg = True
print(get_price(token, decimals, pair_contract, is_reversed, is_price_in_peg), 'BNB')
JS使用:
var ETHER = Math.pow(10, 18);
var WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
var CAKE_ROUTER_V2 = Web3.utils.toChecksumAddress('0x10ed43c718714eb63d5aa57b78b54704e256024e');
var web3 = new Web3('https://bsc-dataseed1.binance.org:443');
var ABI = [{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"}];
var get_price = async function(token, decimals, pair_contract, is_reverse, is_price_in_peg) {
var price,
peg_reserve = 0,
token_reserve = 0,
res = await pair_contract.methods.getReserves().call(),
reserve0 = res[0],
reserve1 = res[1];
if (is_reverse) {
peg_reserve = reserve0;
token_reserve = reserve1;
} else {
peg_reserve = reserve1;
token_reserve = reserve0;
}
if (token_reserve && peg_reserve) {
if (is_price_in_peg) {
// CALCULATE PRICE BY TOKEN PER PEG
price = (Number(token_reserve) / Number(Math.pow(10, decimals))) / (Number(peg_reserve) / Number(ETHER));
} else {
// CALCULATE PRICE BY PEG PER TOKEN
price = (Number(peg_reserve) / Number(ETHER)) / (Number(token_reserve) / Number(Math.pow(10, decimals)));
}
return price;
}
return Number(0);
};
var token = Web3.utils.toChecksumAddress('0x126f5f2a88451d24544f79d11f869116351d46e1');
var pair = await (await (new web3.eth.Contract(ABI, CAKE_FACTORY_V2))).methods.getPair(token, WBNB).call();
var pair_contract = await new web3.eth.Contract(ABI, pair);
var is_reversed = (await pair_contract.methods.token0().call()) == WBNB;
var decimals = await (await new web3.eth.Contract(ABI, token)).methods.decimals().call();
var is_price_in_peg = true;
console.log(await get_price(token, decimals, pair_contract, is_reversed, is_price_in_peg), 'BNB')
注1:这仅适用于对WBNB具有流动性的代币。如果流动性与其他硬币相反,你必须递归地了解该链中的所有价格,并将它们相互关联,直到你到达WBNB(或其他网络中的任何其他PEG(。
注2。根据https://arxiv.org/pdf/2009.14021.pdf:
预期执行价格(E[p](:当流动性承购人在X/Y进行交易,承购人希望以预期执行价格执行交易E[P](基于AMM算法和X/Y状态(,考虑到预期的滑动。
执行价格(p(:在发行交易的流动性接受者和正在执行的事务(例如,在块中挖掘(,AMM市场X/Y的状态可以改变。这种状态变化可能会导致意外滑动导致执行价格P!=E[P]。
意外价格下滑(p−E[p](:是p和E[p]之间的差异。
意外滑差率((p−E[p](/E[p](:是超出预期价格的意外下滑。
因此,在我们的情况下,E[P]
是get_price()
的结果,P
是getAmounsOut()
除以我们提供的数量(例如1Kwei(的结果,因此我们甚至可以通过最终减去P − E[P]
来计算滑动
尝试WBNB中的用户toChecksumAddress
:
WBNB = w3.toChecksumAddress('0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c')