체인의정석

Solidity&ethers 이벤트 로그 parse.log 직접 파싱하기 및 "data out-of-bounds" 오류 해결기 본문

블록체인/Solidity

Solidity&ethers 이벤트 로그 parse.log 직접 파싱하기 및 "data out-of-bounds" 오류 해결기

체인의정석 2023. 4. 8. 01:30
728x90
반응형

erc20토큰을 전송 하면 nft가 민팅 되는 구조를 만들고 있었는데 문제가 발생하였다.

평소에는

async function pushETHwithdraw(erc20Token, myAddress, provider, abi) {
    clientsETH = []
    console.log("pushETHwithdraw")
    const resObj = {}
    const topic = [erc20Token.filters.WithdrawETH().topics].toString();
    const filter = {
      address: ERC20,
      fromBlock: 28546565,
      topics: [topic]
    };
    const getlogs = await provider.getLogs(filter);
    let iface = new ethers.utils.Interface(abi);
    for (let logs of getlogs) {
      const receipt = await provider.getTransactionReceipt(logs.transactionHash);
      receipt.logs.forEach((log) => {
        const parsedLog = iface.parseLog(log)
        if( parsedLog.topic == topic) {
            resObj.amount = parsedLog.args.from.toString();
            resObj.buyer = parsedLog.args.to;
            resObj.txhash = logs.transactionHash;
            clientsETH.push({"amount": (resObj.amount/(10**18)).toString(), "buyer": resObj.buyer, "txhash" : resObj.txhash});
        } else {
          console.log(`this topic is not Transfer`)
        }
      });
    }
    return clientsETH;
}

이런식으로 로그를 파싱했는데

문제는 erc721과 erc20의 표준이 같기 때문에 해당 부분이 같은 트랜잭션 안에 있다면 Parse log가 먹히지 않는 것이다.

이때 data out-of-bounds 오류가 나오는데 이는 일반적으로 abi가 잘못되었을 때 나온다.

그러나 이렇게 동일한 이벤트가 발생할때도 오류가 나온다.

그럼 parseLog없이 이벤트를 파싱하는 방법을 쓸 수 밖에 없다.

 

async function pushNFTmint(erc721Token, myAddress, provider, abi) {
    clientsNFT = []
    console.log("pushNFTmint")
    const resObj = {}
    const topic = [erc721Token.filters.Transfer().topics].toString();
    // const topic = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("NFTBuy(address,uint256"));
    const filter = {
      address: ERC721,
      fromBlock: 28727518,
      topics: [topic]
    };
    const getlogs = await provider.getLogs(filter);
    console.log("getlogs", getlogs)
    let iface = new ethers.utils.Interface(abi);
    for (let logs of getlogs) {
      const receipt = await provider.getTransactionReceipt(logs.transactionHash);
      console.log("receipt", receipt)
      receipt.logs.forEach((log) => {
        console.log("log.address", log.address);
        if( log.topics[0] == topic && log.address == ERC721) {
            console.log(`this topic is correct`, topic)
            resObj.from = "0x" + log.topics[1].slice(26);
            console.log(`resObj.from`, resObj.from)
            resObj.to = "0x" + log.topics[2].slice(26);
            console.log(`resObj.to`, resObj.to)
            resObj.tokenId = parseInt(log.topics[3], 16);
            console.log(resObj.tokenId)          ;
            resObj.txhash = logs.transactionHash;
            clientsNFT.push({"from": resObj.from, "to": resObj.to, "tokenId": resObj.tokenId,"txhash" : resObj.txhash});
        } else {
            console.log(`this topic is not Transfer`,topic)
        }
    });
    }
    return clientsNFT;
}

해당 부분은 이런식으로 직접 slice 와 parseInt를 사용하여 해결할 수 있다.

이렇게 모종의 이유로 input값이나 이벤트 등을 파싱해주는 함수가 오류가 날 경우 그냥 16진수에서 데이터를 뽑아내면 된다.

728x90
반응형
Comments