@gooddollar/goodprotocol
Version:
GoodDollar Protocol
443 lines (383 loc) • 18.3 kB
text/typescript
import { groupBy, range, sortBy } from "lodash";
import PromisePool from "async-promise-pool";
import fs from "fs";
import { Provider, setMulticallAddress } from "ethers-multicall";
import { ethers } from "hardhat";
import { Retrier } from "@jsier/retrier";
import { BigNumber } from "ethers";
import EthDater from "ethereum-block-by-date";
setMulticallAddress(122, "0x3CE6158b7278Bf6792e014FA7B4f3c6c46fe9410");
// "https://celo-mainnet-archive.allthatnode.com" : "https://explorer-node.fuse.io"
const celoProvider = new ethers.providers.JsonRpcProvider("https://celo-mainnet-archive.allthatnode.com");
const fuseProvider = new ethers.providers.JsonRpcProvider("https://explorer-node.fuse.io");
const ethProvider = new ethers.providers.JsonRpcProvider("https://ethereum-mainnet-archive.allthatnode.com");
const GD_CELO = "0x62B8B11039FcfE5aB0C56E502b1C372A3d2a9c7A";
const GD_FUSE = "0x495d133B938596C9984d462F007B676bDc57eCEC";
const GD_ETH = "0x67C5870b4A41D4Ebef24d2456547A03F1f3e094B";
const ETH_BRIDGES = [
"0xd17652350cfd2a37ba2f947c910987a3b1a1c60d",
"0xa3247276DbCC76Dd7705273f766eB3E8a5ecF4a5",
"0xD5D11eE582c8931F336fbcd135e98CEE4DB8CCB0",
"0x17B09b22823F00BB9b8ee2d4632E332cadC29458"
];
const CELO_MULTIBRIDGE = "0xf27Ee99622C3C9b264583dACB2cCE056e194494f";
const CELO_MPBBRIDGE = "0xa3247276DbCC76Dd7705273f766eB3E8a5ecF4a5";
let gd = new ethers.Contract(
GD_CELO,
[
"event Transfer(address indexed from, address indexed to, uint amount)",
"function balanceOf(address) view returns(uint256)",
"function totalSupply() view returns(uint256)"
],
celoProvider
);
const multiBridge = new ethers.Contract(
CELO_MULTIBRIDGE,
[
"event LogAnySwapOut(address indexed token,address indexed from,address indexed to,uint256 amount,uint256 fromChainID,uint256 toChainID)",
"event LogAnySwapIn(bytes32 indexed txhash,address indexed token,address indexed to,uint256 amount,uint256 fromChainID, uint256 toChainID)"
],
celoProvider
);
const mpbBridge = new ethers.Contract(
CELO_MPBBRIDGE,
[
"event BridgeRequest(address indexed from,address indexed to,uint256 targetChainId,uint256 normalizedAmount,uint256 timestamp,uint8 bridge,uint256 indexed id)",
"event ExecutedTransfer(address indexed from,address indexed to,uint256 normalizedAmount,uint256 fee,uint256 sourceChainId,uint8 bridge,uint256 indexed id)"
],
celoProvider
);
const main = async () => {
console.log("starting...");
// let mintFuse = await getTransferEvents(
// gd.connect(new ethers.providers.JsonRpcProvider("https://rpc.fuse.io")).attach(GD_FUSE),
// ethers.constants.AddressZero,
// 6000000,
// undefined
// );
// fs.writeFileSync("mintFuse.json", JSON.stringify(mintFuse, null, 2));
// mintFuse.forEach(log => (log.amount = log.args.amount.toString()));
// const mintFuse = JSON.parse(fs.readFileSync("mintFuse.json").toString());
// let mintCelo = await getTransferEvents(gd, ethers.constants.AddressZero, 17000000, undefined);
// fs.writeFileSync("mintCelo.json", JSON.stringify(mintCelo, null, 2));
if (false) {
let multiOut = await fetch(
"https://explorer.celo.org/mainnet/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0xf27Ee99622C3C9b264583dACB2cCE056e194494f&topic0=0x97116cf6cd4f6412bb47914d6db18da9e16ab2142f543b86e207c24fbd16b23a&topic1=0x0000000000000000000000005566b6e4962ba83e05a426ad89031ec18e9cadd3&topic0_1_opr=and"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("multiOut");
let multiIn = await fetch(
"https://explorer.celo.org/mainnet/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0xf27Ee99622C3C9b264583dACB2cCE056e194494f&topic0=0xaac9ce45fe3adf5143598c4f18a369591a20a3384aedaf1b525d29127e1fcd55&topic2=0x0000000000000000000000005566b6e4962ba83e05a426ad89031ec18e9cadd3&topic0_2_opr=and"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("multiIn");
let multiInFuse = await fetch(
"https://explorer.fuse.io/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0x735aBE48e8782948a37C7765ECb76b98CdE97B0F&topic0=0xaac9ce45fe3adf5143598c4f18a369591a20a3384aedaf1b525d29127e1fcd55&topic2=0x000000000000000000000000031b2b7c7854dd8ee9c4a644d7e54ad17f56e3cb&topic0_2_opr=and"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("multiInFuse");
let multiOutFuse = await fetch(
"https://explorer.fuse.io/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0x735aBE48e8782948a37C7765ECb76b98CdE97B0F&topic0=0x97116cf6cd4f6412bb47914d6db18da9e16ab2142f543b86e207c24fbd16b23a&topic1=0x000000000000000000000000031b2b7c7854dd8ee9c4a644d7e54ad17f56e3cb&topic0_1_opr=and"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("multiOutFuse");
let mpbOut = await fetch(
"https://explorer.celo.org/mainnet/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0xa3247276DbCC76Dd7705273f766eB3E8a5ecF4a5&topic0=0xabeeb7182c7294cd8efcd40e9ff952c1b759c2165b3634aac589429de5d55ad0"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("mpbOut");
let mpbIn = await fetch(
"https://explorer.celo.org/mainnet/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0xa3247276DbCC76Dd7705273f766eB3E8a5ecF4a5&topic0=0x6cf712ce908185c8c38a073b7315f79687e7440fb057d9d1ca76a2509a1282ee"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("mpbIn");
let mpbOutFuse = await fetch(
"https://explorer.fuse.io/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0xa3247276DbCC76Dd7705273f766eB3E8a5ecF4a5&topic0=0xabeeb7182c7294cd8efcd40e9ff952c1b759c2165b3634aac589429de5d55ad0"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("mpbOutFuse");
let mpbInFuse = await fetch(
"https://explorer.fuse.io/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0xa3247276DbCC76Dd7705273f766eB3E8a5ecF4a5&topic0=0x6cf712ce908185c8c38a073b7315f79687e7440fb057d9d1ca76a2509a1282ee"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("mpbInFuse");
let outFuse = await fetch(
"https://explorer.fuse.io/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0x495d133B938596C9984d462F007B676bDc57eCEC&topic0=0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef&topic1=0x000000000000000000000000d39021db018e2caeadb4b2e6717d31550e7918d0&topic2=0x0000000000000000000000000000000000000000000000000000000000000000&topic1_2_opr=and&topic0_1_opr=and&topic0_2_opr=and"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("outFuse");
let inFuse = await fetch(
"https://explorer.fuse.io/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0xD39021DB018E2CAEadb4B2e6717D31550e7918D0&topic0=0x2f9a6098d4503a127779ba975f5f6b04f842362b1809f346989e9abc0b4dedb6"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("inFuse");
let outFuse2 = await fetch(
"https://explorer.fuse.io/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0x495d133B938596C9984d462F007B676bDc57eCEC&topic0=0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef&topic1=0x000000000000000000000000e24957CB0f0001A03314C72E6EBC331436e2f7F60&topic2=0x0000000000000000000000000000000000000000000000000000000000000000&topic1_2_opr=and&topic0_1_opr=and&topic0_2_opr=and"
)
.then(_ => _.json())
.then(_ => _.result);
console.log("outFuse");
let inFuse2 = await fetch(
"https://explorer.fuse.io/api?module=logs&action=getLogs&fromBlock=0&toBlock=latest&address=0xe24957CB0f0001A03314C72E6EBC331436e2f7F6&topic0=0x6fc115a803b8703117d9a3956c5a15401cb42401f91630f015eb6b043fa76253"
)
.then(_ => _.json())
.then(_ => _.result);
mpbIn.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256", "uint256", "uint8"], log.data);
log.amount = log.params[0];
});
mpbOut.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256", "uint256", "uint8"], log.data);
log.amountOut = log.params[1];
});
mpbInFuse.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256", "uint256", "uint8"], log.data);
log.amount = log.params[0];
});
mpbOutFuse.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256", "uint256", "uint8"], log.data);
log.amountOut = log.params[1];
});
multiIn.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256", "uint256"], log.data);
log.amount = log.params[0];
});
multiOut.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256", "uint256"], log.data);
log.amountOut = log.params[0];
});
multiInFuse.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256", "uint256"], log.data);
log.amount = log.params[0];
});
multiOutFuse.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256", "uint256"], log.data);
log.amountOut = log.params[0];
});
inFuse.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256"], log.data);
log.amount = log.params[0];
});
outFuse.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256"], log.data);
log.amountOut = log.params[0];
});
outFuse2.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["uint256"], log.data);
log.amountOut = log.params[0];
});
inFuse2.forEach(log => {
log.params = ethers.utils.defaultAbiCoder.decode(["address", "uint256", "bytes32"], log.data);
log.amount = log.params[1];
});
// console.log({
// mpbOut: mpbOut.length,
// mpbIn: mpbIn.length,
// multiOut: multiOut.length,
// multiIn: multiIn.length,
// multiInFuse: multiInFuse.length,
// multiOutFuse: multiOutFuse.length,
// mpbInFuse: mpbInFuse.length,
// mpbOutFuse: mpbOutFuse.length,
// inFuse: inFuse.length,
// outFuse: outFuse.length,
// inFuse2: inFuse2.length,
// outFuse2: outFuse2.length
// // mintFuse: mintFuse.length
// });
// // const found = []
// // .concat(mpbIn, multiIn, multiInFuse, mpbInFuse, inFuse)
// // .filter(_ => _.params[0].gt(ethers.constants.WeiPerEther.mul(180000000)));
// const found = [].concat(mpbIn, multiIn, multiInFuse, mpbInFuse, inFuse, inFuse2);
// const bytx = Object.entries(groupBy(found, _ => _.transactionHash)).filter((k, v) => (v as any).length > 1);
// console.log({ bytx });
// // const bridgeMintsTxs = found.map(_ => _.transactionHash);
// // const nonBridgeMints = mintCelo.filter(l => !bridgeMintsTxs.includes(l.transactionHash));
// // console.log(
// // "nonbridgemints celo:",
// // nonBridgeMints.map(_ => _.transactionHash)
// // );
// // return;
// let totalMpbOut = mpbOut
// .filter(_ => _.params[0].eq(1))
// .reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[1])), ethers.constants.Zero);
// let totalMpbIn = mpbIn
// .filter(_ => _.params[2].eq(1))
// .reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])), ethers.constants.Zero);
// totalMpbOut = mpbOutFuse
// .filter(_ => _.params[0].eq(1))
// .reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[1])), totalMpbOut);
// totalMpbIn = mpbInFuse
// .filter(_ => _.params[2].eq(1))
// .reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])), totalMpbIn);
// let totalMultiOut = multiOut
// .filter(l => l.params[2].eq(1))
// .reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])), ethers.constants.Zero);
// let totalMultiIn = multiIn
// .filter(l => l.params[1].eq(1))
// .reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])), ethers.constants.Zero);
// totalMultiOut = multiOutFuse
// .filter(l => l.params[2].eq(1))
// .reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])), totalMultiOut);
// totalMultiIn = multiInFuse
// .filter(l => l.params[1].eq(1))
// .reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])), totalMultiIn);
// let totalInFuse = inFuse.reduce((prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])), ethers.constants.Zero);
// let totalOutFuse = outFuse.reduce(
// (prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])),
// ethers.constants.Zero
// );
// let totalInFuse2 = inFuse2.reduce(
// (prev, cur) => prev.add(ethers.BigNumber.from(cur.params[0])),
// ethers.constants.Zero
// );
// let totalOutFuse2 = outFuse2.reduce(
// (prev, cur) => prev.add(ethers.BigNumber.from(cur.params[1])),
// ethers.constants.Zero
// );
// console.log({
// totalMpbOut,
// totalMpbIn,
// totalMultiOut,
// totalMultiIn,
// totalInFuse,
// totalOutFuse,
// totalInFuse2,
// totalOutFuse2
// });
// const all = [].concat(
// mpbIn.filter(_ => _.params[2].eq(1)),
// mpbOut.filter(_ => _.params[0].eq(1)),
// multiIn.filter(l => l.params[1].eq(1)),
// multiOut.filter(l => l.params[2].eq(1)),
// multiInFuse.filter(l => l.params[1].eq(1)),
// multiOutFuse.filter(l => l.params[2].eq(1)),
// mpbInFuse.filter(_ => _.params[2].eq(1)),
// mpbOutFuse.filter(_ => _.params[0].eq(1)),
// inFuse,
// outFuse,
// outFuse2,
// inFuse2
// );
// fs.writeFileSync("allBridgeEvents.json", JSON.stringify(all));
}
const all = JSON.parse(fs.readFileSync("allBridgeEvents.json").toString());
let counter = 0;
let total = ethers.constants.Zero;
const gdEth = gd.connect(ethProvider).attach(GD_ETH);
const sorted = sortBy(all, _ => Number(_.timeStamp));
console.log(sorted.slice(0, 10));
const ethDater = new EthDater(ethProvider);
const fuseDater = new EthDater(fuseProvider);
const celoDater = new EthDater(celoProvider);
for (let log of sorted) {
if (log.amountOut) {
log.amountOut = ethers.BigNumber.from(log.amountOut.hex);
total = total.sub(
log.amountOut.gte(ethers.constants.WeiPerEther)
? log.amountOut.div(ethers.constants.WeiPerEther)
: log.amountOut.div(100)
);
}
if (log.amount) {
log.amount = ethers.BigNumber.from(log.amount.hex);
total = total.add(
log.amount.gte(ethers.constants.WeiPerEther)
? log.amount.div(ethers.constants.WeiPerEther)
: log.amount.div(100)
);
}
counter++;
if (
counter >= 1040 ||
(counter >= 950 && counter % 10 === 0) ||
counter % 100 === 0 ||
counter >= sorted.length - 1
) {
// const [tx, tx2] = await Promise.all([
// fuseProvider.getTransaction(log.transactionHash),
// celoProvider.getTransaction(log.transactionHash)
// ]);
const timestamp = Number(log.timeStamp);
const [ethBlock, fuseBlock, celoBlock] = await Promise.all([
ethDater.getDate(timestamp * 1000, false, false),
fuseDater.getDate(timestamp * 1000, true, false),
celoDater.getDate(timestamp * 1000, true, false)
]);
console.log("counter:", counter, timestamp, { ethBlock, fuseBlock, celoBlock });
const res = await Promise.all(
ETH_BRIDGES.map(b => gdEth.balanceOf(b, { blockTag: ethBlock.block }).catch(_ => ethers.constants.Zero))
);
const [onFuse, onCelo] = await Promise.all([
gd
.connect(fuseProvider)
.attach(GD_FUSE)
.totalSupply({ blockTag: fuseBlock.block })
.catch(_ => ethers.constants.Zero),
gd.totalSupply({ blockTag: celoBlock.block }).catch(_ => ethers.constants.Zero)
]);
const onBridges = res.reduce((prev, cur) => prev.add(cur), ethers.constants.Zero).div(100);
console.log(
"bridged:" + total.toString(),
"on bridges:" + onBridges.toString(),
"on chains:",
onCelo.div(ethers.constants.WeiPerEther).add(onFuse.div(100)).toString(),
"time:",
timestamp,
{
onFuse,
onCelo
},
res.map(_ => _.toString())
);
}
}
//
// console.log(txs.length);
// fs.writeFileSync("stuckgd.json", JSON.stringify(txs));
};
const getTransferEvents = async (gd, from, fromBlock, toBlock) => {
const curBlock = toBlock || (await gd.provider.getBlockNumber());
let txs = [];
const f = gd.filters.Transfer(from, null);
const STEP_SIZE = 10000;
const fromBlocks = range(fromBlock, curBlock, STEP_SIZE);
const pool = new PromisePool({ concurrency: 2 });
console.log({ curBlock });
fromBlocks.forEach(start => {
pool.add(async () => {
const options = { limit: 3, delay: 2000 };
const retrier = new Retrier(options);
const results = await retrier
.resolve(() => gd.queryFilter(f, start, start + STEP_SIZE))
.catch(e => console.warn("queryfilter failed:", { start }));
if (!results) return;
txs = txs.concat(results);
console.log({ start }, results.length);
});
});
await pool.all();
return txs;
};
// const analyze = () => {
// const txs = JSON.parse(fs.readFileSync("stuckgd.json").toString());
// let value = 0;
// console.log(txs[0]);
// txs.forEach(tx => {
// value += Number(tx.args[2].hex);
// console.log(`erc20,${GD_CELO},${tx.args[0]},${Number(tx.args[2].hex) / 1e18},`);
// });
// console.log(txs.length, { value });
// };
// analyze();
main().catch(e => console.error("Error:", e.message));