$7 SBC Detour: 69 Line CUB Price Feed Discord Bot

in Programming & Dev4 years ago

nice

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.

Sort:  

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.