Evg*_*kov 3 python blockchain smartcontracts web3js web3py
我正在使用 Web3.py,但遇到了一些奇怪的事情。
对于以下代码(使用 Pancake Router 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())
Run Code Online (Sandbox Code Playgroud)
我得到以下信息:
[1, 19]
[1, 160]
Run Code Online (Sandbox Code Playgroud)
WBNB 和 CAKE 有 18 位小数,KONGSHIBA 有 17 位
。CAKE 目前的价值约为 27.7 美元,WBNB 为 545.41291093 美元
,KONGSHIBA 为 0.00000000000000000332 美元。
所以我应该回来:
[1, 19]
[1, 16000000000000000000]
Run Code Online (Sandbox Code Playgroud)
请指教。
Evg*_*kov 11
计算代币价格的正确方法是询问流动性池(该代币与本地 PEG 或某些美元代币的对)插入的 PEG 数量与代币数量的比率(有关流动性的更多详细信息)池表示,请参阅https://uniswap.org/docs/v2/core-concepts/pools/)。
\n所以对于 python 使用:
\nfrom web3 import Web3\nfrom web3.middleware import geth_poa_middleware # Needed for Binance\n\nfrom json import loads\nfrom decimal import Decimal\n\n\nETHER = 10 ** 18\n\nWBNB = \'0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c\'\nCAKE_ROUTER_V2 = web3.toChecksumAddress(\'0x10ed43c718714eb63d5aa57b78b54704e256024e\')\n\nweb3 = Web3(Web3.HTTPProvider(\'https://bsc-dataseed1.binance.org:443\'))\nweb3.middleware_onion.inject(geth_poa_middleware, layer=0) # Again, this is needed for Binance, not Ethirium\n\nABI = 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"}]\')\n\ndef get_price(token, decimals, pair_contract, is_reversed, is_price_in_peg):\n peg_reserve = 0\n token_reserve = 0\n (reserve0, reserve1, blockTimestampLast) = pair_contract.functions.getReserves().call()\n \n if is_reversed:\n peg_reserve = reserve0\n token_reserve = reserve1\n else:\n peg_reserve = reserve1\n token_reserve = reserve0\n \n if token_reserve and peg_reserve:\n if is_price_in_peg:\n # CALCULATE PRICE BY TOKEN PER PEG\n price = (Decimal(token_reserve) / 10 ** decimals) / (Decimal(peg_reserve) / ETHER)\n else:\n # CALCULATE PRICE BY PEG PER TOKEN\n price = (Decimal(peg_reserve) / ETHER) / (Decimal(token_reserve) / 10 ** decimals)\n \n return price\n \n return Decimal(\'0\')\n\n\nif __name__ == \'__main__\':\n CAKE_FACTORY_V2 = web3.eth.contract(address=CAKE_ROUTER_V2, abi=ABI).functions.factory().call()\n\n token = web3.toChecksumAddress(\'0x126f5f2a88451d24544f79d11f869116351d46e1\')\n pair = web3.eth.contract(address=CAKE_FACTORY_V2, abi=ABI).functions.getPair(token, WBNB).call()\n pair_contract = web3.eth.contract(address=pair, abi=ABI)\n is_reversed = pair_contract.functions.token0().call() == WBNB\n decimals = web3.eth.contract(address=token, abi=ABI).functions.decimals().call()\n is_price_in_peg = True\n\n print(get_price(token, decimals, pair_contract, is_reversed, is_price_in_peg), \'BNB\')\n\n\nRun Code Online (Sandbox Code Playgroud)\n对于 JS 使用:
\nvar ETHER = Math.pow(10, 18);\n\nvar WBNB = \'0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c\';\nvar CAKE_ROUTER_V2 = Web3.utils.toChecksumAddress(\'0x10ed43c718714eb63d5aa57b78b54704e256024e\');\n\nvar web3 = new Web3(\'https://bsc-dataseed1.binance.org:443\');\n\nvar 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"}];\n\n\nvar get_price = async function(token, decimals, pair_contract, is_reverse, is_price_in_peg) {\n var price,\n peg_reserve = 0,\n token_reserve = 0,\n res = await pair_contract.methods.getReserves().call(),\n reserve0 = res[0],\n reserve1 = res[1];\n \n if (is_reverse) {\n peg_reserve = reserve0;\n token_reserve = reserve1;\n } else {\n peg_reserve = reserve1;\n token_reserve = reserve0;\n }\n \n if (token_reserve && peg_reserve) {\n if (is_price_in_peg) {\n // CALCULATE PRICE BY TOKEN PER PEG\n price = (Number(token_reserve) / Number(Math.pow(10, decimals))) / (Number(peg_reserve) / Number(ETHER));\n } else {\n // CALCULATE PRICE BY PEG PER TOKEN\n price = (Number(peg_reserve) / Number(ETHER)) / (Number(token_reserve) / Number(Math.pow(10, decimals)));\n }\n \n return price;\n }\n \n return Number(0);\n};\n\n\nvar token = Web3.utils.toChecksumAddress(\'0x126f5f2a88451d24544f79d11f869116351d46e1\');\nvar pair = await (await (new web3.eth.Contract(ABI, CAKE_FACTORY_V2))).methods.getPair(token, WBNB).call();\nvar pair_contract = await new web3.eth.Contract(ABI, pair);\nvar is_reversed = (await pair_contract.methods.token0().call()) == WBNB;\nvar decimals = await (await new web3.eth.Contract(ABI, token)).methods.decimals().call();\nvar is_price_in_peg = true;\n\nconsole.log(await get_price(token, decimals, pair_contract, is_reversed, is_price_in_peg), \'BNB\')\nRun Code Online (Sandbox Code Playgroud)\n注 1:这仅适用于对 WBNB 具有流动性的代币。如果流动性针对其他某种代币,您必须递归地了解该链中的所有价格并将它们相互关联,直到达到 WBNB(或其他网络中的任何其他 PEG)。
\n注2.根据https://arxiv.org/pdf/2009.14021.pdf:
\n\n\n预期执行价格 (E[P]):当流动性\n接受者在 X/Y 上发出交易时,\n接受者希望以\n预期执行价格\nE[P]执行交易(基于 AMM 算法和 X/ Y 状态),\n考虑到预期的滑点。
\n
\n\n执行价格 (P):在流动性接受者发出交易与执行交易(例如在区块中开采)之间的时间差期间,AMM 市场 X/Y 的状态可能会发生变化。这种状态变化可能会发生变化。引起意外滑点\n导致执行价格 P != E[P]。
\n
\n\n意外价格滑点 (P \xe2\x88\x92 E[P]):是 P 和 E[P] 之间的差值。
\n
\n\n意外滑点率 ((P \xe2\x88\x92 E[P]) / E[P]):是\n超过预期价格的意外滑点。
\n
因此,在我们的情况下,是E[P]我们的结果, 是金额(例如 1Kwei)除以我们提供的金额(本例中为 1K)的结果,因此我们甚至可以通过最终减去来计算滑点get_price()PgetAmounsOut()P \xe2\x88\x92 E[P]