V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
czz5242199
V2EX  ›  问与答

通过程序监控 pancakeswap 中 babydoge 的交易数据

  •  
  •   czz5242199 · 2021-07-02 14:24:52 +08:00 · 2324 次点击
    这是一个创建于 1238 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目出发点

    最近在币安 bsc 链上有一个很火的币叫babydoge,目前还没有上主流交易所,而是在 bsc 链上的去中心化交易所 pancakeswap 上,所以作为程序员,我们就可以通过监控链上数据来监控整个这个币的买卖。

    开发思路

    • 监控 babydoge 合约的 Transfer 事件
    • 查询这个 Transfer 事件所对应的 Transaction 是否来自于 PancakeSwap,如果不是说明本次只是一次普通的转账,直接丢弃即可
    • 如果是,下一步就是算出本次买 /卖了多少个 babydoge,对应的资产价值是多少 USDT (美元)
    • 将结果存入数据库做实时分析监控

    下面我们一步一步完成整个开发

    1 、开发环境

    • 开发语言为 Javascript + Node.js
    • 通过 ethers.js 和链交互
    • 使用 express.js 做 http 服务器
    • 使用 prisma 作为 orm 和数据库交互(我使用的 postgresql )

    2 、监控 Transfer 事件

    我们从币安区块链浏览器中找到 babydoge 的合约地址: https://bscscan.com/token/0xc748673057861a797275CD8A068AbB95A902e8de

    可以看出这是一个 ERC20 的合约,我们直接通过 bsc 官方节点构造一个 provider 开始监听 Transfer 事件

    const provider = ethers.getDefaultProvider('https://bsc-dataseed.binance.org/'); 
    const filter = {
        address: babydogeAddress,
        topics: [ethers.utils.id('Transfer(address,address,uint256)')],
    };
    provider.on(filter, analyseTransferEvent);
    

    这样就可以将所有的 Transfer 事件全部转移给 analyseTransferEvent 函数处理

    3 、获取本次交易的相关数据

    我们可以从 event 事件中拿到本次交易的 hash 值,然后通过 provider 获取到完整的数据

    async function analyseTransferEvent(event) {
        // 获取 transaction 详情
        const res = await provider.getTransaction(event.transactionHash);
        if (res.to !== pancakeAddress) {
            // 可能是一笔普通转账,不是 pancake 交易
            return;
        }
    }
    
    

    同时,我们可以将不是来自 pancakeswap 的数据直接丢弃(普通转账类型)

    然后是如何获取本次交易的类型(买 /卖)和交易 babydoge 数量,这里我们需要利用 babydoge 的 abi 生成一个数据解析器来解析 event 事件,babydoge 的 abi 信息可以直接从区块链浏览器中获取 https://bscscan.com/address/0xc748673057861a797275CD8A068AbB95A902e8de#code

    代码如下

    const babydogeInterface = new ethers.utils.Interface(babydogeAbi);
    // 解析 event
    const parsedEvent = babydogeInterface.parseLog(event);
    // 交易发起人
    const address = res.from;
    // 买 /卖
    const action = address === parsedEvent.args.from ? 'SELL' : 'BUY';
    // 交易数量 去掉后 9 位( babydoge 有 9 位精度)
    const amount = Number(parsedEvent.args.value) / 1e9;
    

    最后是最麻烦的怎么知道用户本次交易的资金是多少,价值多少美金,我分析了 pancakeswap 的源码,发现总有以下几种交易类型

    • 用 BNB 和 babydoge 交易
    • 用 wBNB 和 babydoge 交易
    • 用 美元类代币(BUSD, BSC-USD) 和 babydoge 交易
    • 用 其他不知道 ERC20 币,通过 BNB/BUSD 中转,和 Babydoge 交易

    最终我定下的代码策略是这样的

    • 对于 BNB 或者 wBNB 代币交易,直接乘以 bnb 价格即可(通过爬虫维护一个 bnb 的实时价格 https://bscscan.com/ 从这个网站左上角就有)
    • 对于使用美元代币的交易,直接拿到数量即可
    • 对于使用其他 ERC20 代币的交易,我们直接 bsc 官方浏览器通过爬虫爬取本次的价格(这种交易比例低)

    最终部分代码如下

    
    async function analyseTransferEvent(event) {
        // 获取 transaction 详情
        const res = await provider.getTransaction(event.transactionHash);
        if (res.to !== pancakeAddress) {
            // 可能是一笔普通转账,不是 pancake 交易
            return;
        }
        // 解析 input 数据
        const input = pancakeInterface.parseTransaction({ data: res.data, value: res.value });
    
        // 解析 event
        const parsedEvent = babydogeInterface.parseLog(event);
        // 获取 transfer 事件的数据 from -> to, value
    
        const address = res.from;
        // 本次交易的总价值
        let usdValue = 0;
        // 买 /卖
        const action = address === parsedEvent.args.from ? 'SELL' : 'BUY';
        // 交易数量 去掉后 9 位
        const amount = Number(parsedEvent.args.value) / 1e9;
    
        if (!input.name.includes('swap')) {
            return;
        }
        if (input.name.includes('ETH')) {
            // swapExactETHForTokens
            // swapExactETHForTokensSupportingFeeOnTransferTokens
            // swapExactTokensForETH
            // swapExactETHForTokensSupportingFeeOnTransferTokens
            // 使用 bnb 交易的 4 个方法
            let bnb;
            if (res.value > 0) {
                // 用 bnb 买
                bnb = Number(res.value);
            } else {
                // 卖成了 wBNB 交易
                bnb = Number(input.args.amountOutMin);
            }
            usdValue = (getBnbPrice() * bnb) / 1e18;
        } else {
            // 用其他货币买或者卖
            const path = input.args.path.map((it) => it.toLowerCase());
            let inAmount, outAmount;
            if (input.name.includes('swapExactTokensForTokens')) {
                inAmount = Number(input.args.amountIn);
                outAmount = Number(input.args.amountOutMin);
            } else if (input.name.includes('swapTokensForExactTokens')) {
                inAmount = Number(input.args.amountInMax);
                outAmount = Number(input.args.amountOut);
            }
            if (action === 'BUY' && wBnbAddress === path[0]) {
                // 使用 wBnb 购买
                usdValue = (getBnbPrice() * inAmount) / 1e18;
            } else if (action === 'BUY' && usdAddress.includes(path[0])) {
                // 使用 busd 购买
                usdValue = inAmount / 1e18;
            } else if (action === 'SELL' && usdAddress.includes(_.last(path))) {
                // 卖成 busd
                usdValue = outAmount / 1e18;
            } else {
                // 使用非标准代币,从币安网站爬虫算一下价格
                usdValue = await usdValueFromBinance(event.transactionHash);
                if (!usdValue) {
                    console.log(`价格爬虫失败`, event.transactionHash);
                    return;
                }
            }
        }
        if (usdValue < 1) {
            // 忽略 1 美元以下的交易
            return;
        }
    
        // 将数据存到数据库
        ......
    }
    

    最终实现效果如下:

    image.png

    受到马斯克喊单的影响,babydoge 交易量巨增,代码运用 2 天积累了 14 万条交易数据

    image.png

    同时做了一些对大户数据的监控,查看大户倾向是买多还是卖多

    联系作者

    telegram: @zhuozhongcao 微信:18801971372

    1 条回复    2021-07-08 22:07:05 +08:00
    Elmer
        1
    Elmer  
       2021-07-08 22:07:05 +08:00
    BabyDoge to the moon 🚀🚀🚀
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2416 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 16:07 · PVG 00:07 · LAX 08:07 · JFK 11:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.