Trees
I've been branching out a bit and exploring BSC/ETH after getting into Cub. My goal is to get the block-by-block price history of CUB, and this script is based on my progress so far.
Here's a quick and dirty 69 lines of python that will post the price of CUB to a discord channel when the liquidity pool changes.
import datetime
from decimal import Decimal, getcontext
from time import sleep
from requests import Session
from discord import Webhook, RequestsWebhookAdapter
getcontext().prec = 18
bsc_node = 'https://bsc-dataseed1.ninicoin.io/'
pancake_contract = '0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F'
cub_contract = '0x50D809c74e0B8e49e7B4c65BB3109AbE3Ff4C1C1'
busd_contract = '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56'
cub_busd_contract = '0x0EF564D4F8D6C0ffE13348A32e21EFd55e508e84'
sync_topic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1'
webhook_url = ''
def eth_post(method, params):
j = {
'jsonrpc':'2.0',
'method':f'eth_{method}',
'params':params,
'id':session.id
}
with session.post(bsc_node, json=j) as r:
session.id += 1
return r.json().get('result')
def stream():
block_num = int(eth_post('blockNumber', []), 16)
while True:
block = eth_post('getBlockByNumber', [hex(block_num), True])
if block is None:
sleep(3)
else:
yield (block_num, block)
block_num += 1
ts = datetime.datetime.now(datetime.timezone.utc).timestamp()
dif = ts - int(block['timestamp'], 16)
wait = 3.5 - dif
if (wait > 0):
sleep(wait)
def main():
old_price = Decimal(0)
global session
with Session() as session:
session.id = 1
webhook = Webhook.from_url(url=webhook_url, adapter=RequestsWebhookAdapter(session))
for block_num, block in stream():
for trx in block['transactions']:
if (trx['to'] != pancake_contract.lower()): continue
if (cub_contract[2:].lower() not in trx['input']): continue
receipt = eth_post('getTransactionReceipt', [trx['hash']])
if not int(receipt['status'], 16): continue
for log in receipt['logs']:
if (log['address'] != cub_busd_contract.lower()): continue
if (log['topics'][0] != sync_topic): continue
cub = Decimal(int(log['data'][2:66], 16))
busd = Decimal(int(log['data'][66:130], 16))
price = busd / cub
if (price == old_price): continue
old_price = price
d = datetime.datetime.fromtimestamp(int(block['timestamp'], 16), datetime.timezone.utc)
d = d.replace(tzinfo=None)
message = f'**CUB price: $**`{price}` - block: `{block_num}` - `{d}`'
webhook.send(message, username='Simba')
if __name__ == '__main__':
main()
Disclaimer
The above code is a weird and ugly way to do this, and I'm probably missing some price changes. Really you should just use Web3. Maybe something like this:
import requests
from web3 import Web3
bsc_node = 'https://bsc-dataseed1.ninicoin.io/'
lp_abi_url = 'https://raw.githubusercontent.com/CubFinance/cub-frontend/48092992a10d44e3c621e5516497fd07fe7f5ada/src/config/abi/uni_v2_lp.json'
cub_busd_lp = '0x0EF564D4F8D6C0ffE13348A32e21EFd55e508e84'
with requests.get(lp_abi_url) as r:
lp_abi = r.json()
w3 = Web3(Web3.HTTPProvider(bsc_node))
lp_contract = w3.eth.contract(cub_busd_lp, abi=lp_abi)
a, b, _ = lp_contract.functions.getReserves().call()
print(f'BUSD / CUB: {b / a}')
But anyway it was fun to dig around and learn a bit about BSC/ETH contracts.
Hard-Working Orange Pi
Last post's Hive stream has been running for more than 25 hours now (after a few false starts). The little $7 SBC seems to be having no trouble running 2 whole python scripts. 😄
See the price feed in action over here.
Hive spoiled me with the easier to use API. Working with eth and bsc as much as I have recently makes me hate it tons.
My thoughts exactly. Feels like they designed it to be hard for humans to understand or something.