web3js 監控以太坊代幣交易

監控以太坊交易記錄,監控以太坊代幣交易;

 

如題: 如何監控以太坊交易記錄

一般都是監控代幣轉賬記錄;

erc20標準的轉賬

//轉賬方法
function transfer(address to, uint256 value) public returns (bool);
function transferFrom(address from, address to, uint256 value) public returns (bool);
//轉賬事件,以上兩個交易成功都會發送該事件
event Transfer(address indexed from, address indexed to, uint256 value);

監控方式

  1. 遍歷塊信息,匹配to是否是某代幣,再匹配input或者log,是否是transfer/transferFrom
  2. 使用websocket方式鏈接節點,通過訂閱的方式
  3. 使用etherscan.io/apis
  4. 本文主要介紹的logs方式

    1、掃塊方式

let transaction = await web3.eth.getTransaction(pHash).catch(Common.thenCatch);
if (tr.to === null) {
   //創建智能合約,
}else if(tr.input.length >= 10){
    //調用合約方法
    //再匹配是否調用了某方法
    if (input.startsWith('0xa9059cbb')) {
        //transfer(address,uint256)
      }else if(input.startsWith('0x23b872dd'){
        //transferFrom
      }
}else{
    //轉賬以太坊
}

如果疑惑0xa9059cbb是什麼,可參考鏈接 以太坊實戰【地址監控三】

或者參考 理解以太坊時間與日誌 

web3.sha3("transfer(address,uint256)")

推薦一個通過abi解析input的庫 https://lab.miguelmota.com/ethereum-input-data-decoder/example/

 

2、訂閱的方式監控塊

 這個方式會比較簡單,但是鏈接節點需要通過ws的方式。ws好像比較耗資源..鏈接數多了節點會卡;

使用方法:

1)合約事件訂閱

   參考 http://cw.hubwiz.com/card/c/web3.js-1.0/1/4/13/

    let web3 = AppConfig.getWeb3();
    let contract = new web3.eth.Contract(AppConfig.getErc20Abi(),addr);
    let events = new Array();
    //contract.events.Transfer({fromBlock:0,filter:{to:to}},function (error,event) {
    contract.events.Transfer({fromBlock:0,filter:{from:from}},function (error,event) {
        //
        console.log(event);
    }).on('data',function (log) {
        console.log(log);
    }).on('changed',function (log) {
        console.error('changed-----');
        console.log(log);
    }).on('error',function (log) {
        console.error('error-----');
        console.log(log);
    });

2)直接使用web3.eth訂閱事件

 參考http://cw.hubwiz.com/card/c/web3.js-1.0/1/3/6/

    let obj = {
        // address:'替換'
        topics: ['替換']
    };
    let web3 = ConfigInit.getWeb3();
    subscription = web3.eth.subscribe('logs', obj, function (err, result) {
        console.log(err);
        console.log(result);
    }).on("data", function (log) {
        console.error('data-----');
        console.log(log);
    }).on("changed", function (log) {
        console.error('changed-----');
        console.log(log);
    }).on('error', function (log) {
        console.error('error-----');
        console.log(log);
    });

3、使用etherscan-apis 

  具體查看  https://etherscan.io/apis

  使用訪問限制,看提示是每秒最多5個請求..具體看實測。。那個MyApiKey也可以不註冊使用

使用例子

//測試網
https://api-rinkeby.etherscan.io/api?module=account&action=tokentx&contractaddress=0x00000000&startblock=4936100&endblock=4936200&sort=asc
//主網
https://api.etherscan.io/api?module=account&action=tokentx&contractaddress=0x00000000&startblock=4936100&endblock=4936200&sort=asc
//自行替換裏面的合約地址和start,end塊號

4、通過web3.eth.getPastLogs

 該方法是無意中發現的..之前再羣裏總問別人,除了上述三種方式,還有沒有其他的...沒人答.... 

然後還去找go-ethereum 看有沒有方案,忘了後面怎麼發現了getPastLogs

先說下爲啥不用上面三種

第一種方式:掃to;會有一種地方會漏掉。 比如批量轉代幣(不懂的可以查看 https://blog.csdn.net/zgf1991/article/details/90756619),或者其他合約內部轉賬

使用批量合約轉幣,to是批量合約工具的地址,調用的方法也不是transfer(address,uint256);未知的,合約開發者隨意取名,不過內部還是掉的transfer

第二種方式:ws是因爲我這邊沒有測試節點,主節點怕用了ws卡或搞壞環境;

第三種方式:etherscan-apis;不穩定..萬一請求過快/過多。被限制或被檢測是爬蟲; 就GG了。羣裏有個小夥用這個不是很穩定,還出404~~

好了。正題。。

目前我使用getPastLogs挺好用的, 每隔45-60s調用一次,自行保存最後一次的塊號;

如使用發現問題..請告知一聲

核心代碼如下


MonitorTokensTxLogsUtils.scanBlockTokenTx = async function (startBlock, endBlock) {

    let arr = await MongodbOptions.getAllContract().catch(function (e) {
        log4js.error('查詢mongodb合約列表出錯 ' + e.message);
    });
    if (arr === undefined) {
        //查詢出錯
        return null;
    }
    if (arr.length === 0) {
        log4js.info('未查詢到mongodb合約數據');
    } else {
        let map = new Map();
        for (let i = 0; i < arr.length; i++) {
            map.set(arr[i].address, arr[i].name);
        }
        await getLogs(map, startBlock, endBlock);
    }
    return true;

};

/**
 * 掃區塊,監控入賬
 * 只有交易成功的纔會進入到這裏,交易失敗的,沒有
 * @param tokenMap map(addr=>name);存入時需轉成小寫! 先從數據庫查詢
 * @param startBlock
 * @param endBlock
 */
async function getLogs(tokenMap, startBlock, endBlock) {
    let web3 = ConfigInit.getWeb3();
    let datas = await web3.eth.getPastLogs({fromBlock: startBlock, toBlock: endBlock, topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']}).catch(function (e) {
        log4js.error('查詢交易記錄出錯:startBlock: ' + startBlock + ' -> endBlock: ' + endBlock);
        return null;
    });
    console.log('查詢到' + datas.length + '條數據');
    for (let i = 0; i < datas.length; i++) {
        let item = datas[i];
        let addr = item.address.toLocaleLowerCase();
        console.log(addr);
        if (tokenMap.has(addr)) {
            let to = '0x' + item.topics[2].substring(26);//32字節,20是地址,還有12是補0,加上0x;12*2 = 24 + 2 = 26;
            to = to.toLocaleLowerCase();
            let isAddrExist = await MongodbOptions.checkToAddr(to).catch(Common.thenCatch);
            if (isAddrExist) {
                let tx = item.transactionHash.toLocaleLowerCase();
                let logIndex = item.logIndex;
                //確認交易是否已經存在;
                let txExist = await checkTxExist(tx, logIndex);
                if (txExist) {
                    log4js.info('交易已經存在 ' + tx + ' ' + logIndex + ' ' + to);
                    continue;
                }
                let blockHash = item.blockHash;
                let blockHeight = item.blockNumber;
                let value = web3.utils.fromWei(item.data);
                let blockTimestamp = await getBlockTime(blockHeight);
                reportContract(tx, blockHash, blockHeight, to, value, endBlock, blockTimestamp, logIndex, tokenMap.get(addr));
            }
        }
    }
    return true;
}

如果疑問 topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'] 是什麼;

借鑑下 理解以太坊事件與日誌  文中的代碼

> web3.sha3("Transfer(address,address,uint256)")
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"

topics 內容結構如何解析,可以先自己測試獲取成功,去看實際返回值分析;

參考批量日誌 https://ropsten.etherscan.io/tx/0x630b868e41ecfbd97273371ed33242439230355d9110095b814ae3029b88d829#eventlog

該記錄不是我的...網上摳的~~~

說下我目前的瞭解:

返回的datas是所有發送了Transfer(address,address,uint256)事件的交易記錄;主要都是ERC20代幣

topics[0]是事件方法名,topics[1]是發送者(from) ,topics[2]是接收者(to) 

data是轉賬金額;logIndex是當前交易hash中的日誌id,可以當做當前的唯一標識(是當前塊還是當前hash,需要確認下,忘了...)

其他的自己琢磨吧

 

當前使用web3版本是 "web3": "^1.0.0-beta.55"

如果是java,php自己找找這個方法,應該都有

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章