Skip to content

Commit

Permalink
Create script to find btc withdrawals
Browse files Browse the repository at this point in the history
  • Loading branch information
andresaiello committed Feb 21, 2024
1 parent 45930f0 commit 87c0be2
Showing 1 changed file with 200 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import { ethers, network } from "hardhat";

interface TransactionAnalysisResult {
amount: string;
btcAddress: string;
hash: string;
isSegWit: boolean;
}

// Specify the address you're interested in
const ADDRESS = "0x13A0c5930C028511Dc02665E7285134B6d11A5f4"; // BTC.BTC
const API_ENDPOINT = "zetachain.blockscout.com";
const END_BLOCK = 1857360;

const preCalculatedResults = [
"0xb59145790f705b023fedee9d803642b24221bacc8b285464b58d90d637872b30",
"0xb78d08dc5e8051cec1427fe9343d65e3996fb21ba8f3483c4348dbe72f0e04ce",
"0xc1dfa2f66e9c729d1e85fd2eaf8c5fbd2aee71f7b21d62a94e6d2b216b256fe2",
"0xe07f7758634148491a340128ade1fd9e27c4a0ca02beb7a52c2cedb36dff5976",
"0xdcd9ca7a9be91d10cb22df5e7b850844f26d144eb1884fd0ce1a3a3820358f17",
"0xf5797d3188a54d586d11f4729a87eddfa46b9c8a2e17db79894a4ba428aa954e",
"0xc7aa5681e715c403614635335a04026ad025080a828f60a031437cb22f42df11",
"0xc47f55d77b27f3880bac796a09b53d0aeaae38cea8acd99d3d890d3518cfe580",
"0x78f7b45ccdb7c3266a8a5d7575470001daea7396e58fe232e9c3a749446727f7",
"0xb59145790f705b023fedee9d803642b24221bacc8b285464b58d90d637872b30",
"0xb78d08dc5e8051cec1427fe9343d65e3996fb21ba8f3483c4348dbe72f0e04ce",
"0xc1dfa2f66e9c729d1e85fd2eaf8c5fbd2aee71f7b21d62a94e6d2b216b256fe2",
"0xe07f7758634148491a340128ade1fd9e27c4a0ca02beb7a52c2cedb36dff5976",
"0xdcd9ca7a9be91d10cb22df5e7b850844f26d144eb1884fd0ce1a3a3820358f17",
"0xf5797d3188a54d586d11f4729a87eddfa46b9c8a2e17db79894a4ba428aa954e",
"0xc7aa5681e715c403614635335a04026ad025080a828f60a031437cb22f42df11",
"0xc47f55d77b27f3880bac796a09b53d0aeaae38cea8acd99d3d890d3518cfe580",
"0x78f7b45ccdb7c3266a8a5d7575470001daea7396e58fe232e9c3a749446727f7",
"0xddb732c20c3ac963a1a16eb78d7af2b2c7a73468afd7baf92ef38097c0fc12de",
"0x50e69755f7a815e1ddfc9ef091ea19a7b95099f3ad8befeddf8c2fcd01553c91",
"0xfc57adb390a22a8e54c4ff6cf7280270002d6553185bd90d800b45cf72d7e203",
"0x05a21a369f3045e53d31341e9bd8880254611a4eaa88b00090ec8c542b3fe882",
"0x70c718c714d957ed34930420da379125eb6eaff70cf0103e14e7e3f2afb22542",
"0x5e18c3f68f3b964af8b31d9276329e7e61ffb5d36881a9fc95cee56dea391984",
"0x9bffb2df710d2036ad2dbcfdf5ac3f3783c92e10b55e74fc84bb1fcdc61e31b4",
"0x52e44224ded45bc18ad03cfa6042f244a74b4d3e4778d0cf40a1201e03666c19",
"0x83ae01f16be764e94360ae2f3b8ae219a4c388b0dc2d010993c9b57e53dc1674",
"0xbec21c8e1a411c8397111d7ea666b58a5fcee9eab15e8cf26484c6b46754dad7",
"0x9ac1ec1b723afa4f7a41c5a92199a21575be47c55f815fddf3b6ae8d3404c4bf",
"0x86e41fcd6928e7435bcc925d16f523c7b5e2d611e29e563747eeeb4f19254bef",
"0xa62c69ed5c4632160cfe3ab21fe4e6b1ce24e46642722ea9624c1c6a2123d479",
"0x2e75fc8b803f406f75e01dd61272a1bd291e4943fe50bf65925053f95df7c5ba",
"0x9aaefece38fd2bd87077038a63fffb7c84cc8dd1ed01de134a8504a1f9a410c3",
"0xa1e0d5b75eb08b4f60ffaea7fbcf5090fb75e2e018887799989eea3b12c3e10a",
"0x81126c18c7ca7d1fb7ded6644a87802e91bf52154ee4af7a5b379354e24fb6e0",
"0x6c60cc1218dfa0af9c12bb529f8f21747df53faa1bb995cd60e86e76212a5600",
"0x41ae1ecbf323fc39f149e7f9638800c9540b943d26f6d39002edd64452d85fa4",
"0xcc03addcc86b53cad457b2cc459cde4c8cd68565e1f3abebfbf838bee7dc96ae",
"0x36107b56c9dcf776712abbb0eef95d12e3099f821e163574440046e9b3baee0b",
"0x2f705185db776988b6817fc6ac04d320e81fedb85a522941428321851bec6d9f",
"0x386684d9a6156cc8f54cd34003e147a84bfeaa7c4558f1f10642e913378ce2c5",
"0x4ccb24a326418411562ae0969100ff65a18e60a24558fe503f9defc3a250d411",
"0xd27a67caefe97d4abfdf1c7d1a53cb411a58604c5eabda2e48a26d96cab099e8",
"0xbf9a1b8bc7a1e918a2fc1795e0bb3df0ed4b7146161325580c47fa69c8e8369b",
"0x1e155d7c9e30ab5c65a096cc92f4a40e9cb8d8c0b0416182a5e4784455b4e6cc",
"0x0010d928235a05092dea55eeb4ed45944ff49cb7ec749b01793aadc2c8c74f54",
"0xaf5a6622984421de67f18ab65c565e74d9047d8f38a7266dd8cd14370823f4df",
"0xa059d7149e57c331d3fb13e36c1657160085dcbd5a8c6b01d0f48d271ab60614",
"0x47c482df41abffb5b6827e13afc379b2f843bac2759c6d0eb1d00459f9cb31c5",
"0x77b46aada73de00fa67aa4f72ac47257ddb96b4352851ca3664368bbf0d0ea23",
];

// Function to check if a transaction involves the specified address
const isTransactionOfInterest = (tx: any, address: string) => {
if (tx.hash === "A0x6a8b592fbe88c440e1e491b1d30f4e1a87b4b62df1e37bf5201c885440510bb0") {
console.log(tx);
}
try {
const isBTCDestination = tx?.to?.toLowerCase() === address.toLowerCase();
const isWithdraw = tx?.input?.toLowerCase().includes("0xc7012626");
const isError = tx?.isError === "1";
return isBTCDestination && isWithdraw && !isError;
} catch (e) {
console.log(e);
console.log(tx);
}
};

// Main function to iterate over the block range and find transactions
const findTransactionsInRange = async () => {
let totalTx = 0;
let totalErrorTx = 0;
let txHashes: string[] = [];
for (let i = 0; i < END_BLOCK; i++) {
const API_URL = `https://${API_ENDPOINT}/api?module=account&action=txlist&address=${ADDRESS}&sort=asc&filter_by=to&page=${i}&offset=1000`;

try {
const call = await fetch(API_URL);
const response = await call.json();

const result = response.result;
const initBlock = result[0].blockNumber;
const endBlock = result[result.length - 1].blockNumber;

const filteredTx = result.filter((tx: any) => isTransactionOfInterest(tx, ADDRESS));

totalTx += filteredTx.length;
if (filteredTx.length > 0) {
// console.log(filteredTx.map((tx: any) => tx.hash));
txHashes = txHashes.concat(filteredTx.map((tx: any) => tx.hash));
}

if (i % 10 === 0) {
console.log(`Fetching page ${i}`);
console.log(`Fetched block ${initBlock} to ${endBlock}...`);
console.log(`total tx: ${totalTx}`);
}
if (endBlock >= END_BLOCK) {
break;
}
} catch (e) {
console.log(`Error fetching block ${i}`, e);
}
}
console.log(`total tx: ${totalTx} / Errors: ${totalErrorTx}`);
console.log(txHashes);
return txHashes;
};

const hexToString = (hex: string): string => {
const hexWithoutPrefix = hex.startsWith("0x") ? hex.substring(2) : hex;
let str = "";
for (let i = 0; i < hexWithoutPrefix.length; i += 2) {
const byte = parseInt(hexWithoutPrefix.substr(i, 2), 16);
if (byte) str += String.fromCharCode(byte);
}
return str;
};

const isSegWitAddress = (address: string): boolean => {
if (address.startsWith("bc1")) {
return true;
}

if (address.startsWith("3")) {
return true;
}

return false;
};

const decodeInputData = (input: string) => {
const iface = new ethers.utils.Interface(["function withdraw(bytes memory to, uint256 amount)"]);

const decoded = iface.decodeFunctionData("withdraw", input);

const to = decoded[0]; // bytes memory to
const amount = decoded[1]; // uint256 amount

const result: TransactionAnalysisResult = {
amount: amount.toString(),
btcAddress: hexToString(to),
hash: "",
isSegWit: false,
};
return result;
};

const analyzeTransaction = async (txHash: string) => {
const API_URL = `https://${API_ENDPOINT}/api/v2/transactions/${txHash}`;

try {
const call = await fetch(API_URL);
const response = await call.json();
const rawInput = response.raw_input;
const result = decodeInputData(rawInput);
result.isSegWit = isSegWitAddress(result.btcAddress);
result.hash = txHash;

return result;
} catch (e) {
console.log(`Error fetching tx ${txHash}`, e);
}
};

// Call the main function
const main = async () => {
// @dev: findTransactionsInRange takes 20 minutes to run then I pre run it and store the results in preCalculatedResults
// const txHashes = await findTransactionsInRange();
const txHashes = preCalculatedResults;

const results: TransactionAnalysisResult[] = [];
for (const txHash of txHashes) {
const result = await analyzeTransaction(txHash);
result && results.push(result);
}

console.table(results.filter((result) => !result.isSegWit));
console.table(results.filter((result) => result.isSegWit));
};

main().catch((error) => {
console.error(error);
process.exit(1);
});

0 comments on commit 87c0be2

Please sign in to comment.