From 2ae9ea20603d66f0b3cdaaa2ac11ead4a4fc24b1 Mon Sep 17 00:00:00 2001 From: Nikolas Haimerl Date: Tue, 17 Sep 2024 14:45:14 +0000 Subject: [PATCH 1/4] add chain fusion adapter --- src/adapters/chain-fusion/index.ts | 135 +++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 src/adapters/chain-fusion/index.ts diff --git a/src/adapters/chain-fusion/index.ts b/src/adapters/chain-fusion/index.ts new file mode 100644 index 00000000..a08d2a98 --- /dev/null +++ b/src/adapters/chain-fusion/index.ts @@ -0,0 +1,135 @@ +import { + BridgeAdapter, + ContractEventParams, + PartialContractEventParams, +} from "../../helpers/bridgeAdapter.type"; +import { getTxsBlockRangeEtherscan, wait } from "../../helpers/etherscan"; +import { getTxsBlockRangeMerlinScan } from "../../helpers/merlin"; +import { getTxDataFromEVMEventLogs } from "../../helpers/processTransactions"; +import axios from 'axios'; +import { EventData } from "../../utils/types"; + +async function get_erc2Contracts(){ + let api_call = 'https://icrc-api.internetcomputer.org/api/v2/ledgers?network=mainnet&token_types=chain_key&sort_by=ledger_canister_id&include_total_supply_7d=false'; + let response = await axios.get(api_call); + let erc20_contracts = []; + for (let i = 0; i < response.data.data.length; i++) { + let token_info = response.data.data[i]; + if (token_info.token_type === 'chain_key') { + if (token_info.ckerc20_contract !== null) { + erc20_contracts.push(token_info.ckerc20_contract.address); + } + } + } + return erc20_contracts; +} + +const eth_minter_address = "0xb25eA1D493B49a1DeD42aC5B1208cC618f9A9B80"; +const eth_helper_contract = "0x7574eB42cA208A4f6960ECCAfDF186D627dCC175" +const erc20_helper_contract = "0x6abDA0438307733FC299e9C229FD3cc074bD8cC0" +const weth_contract_addresss = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + +const ercDepositEventParams: ContractEventParams = { + target: null, + topic: "ReceivedErc20(address, address, uint256, bytes32)", + abi: [ + "event ReceivedErc20(address indexed erc20_contract_address, address indexed owner, uint256 amount, bytes32 indexed principal)", + ], + argKeys: { + token: "erc20_contract_address", + from: "owner", + amount: "amount", + to: 'principal' + }, + isDeposit: true, +}; + +const ercWithdrawalEventParams: ContractEventParams = { + target: null, + topic: "Transfer(address,address,uint256)", + abi: ["event Transfer(address indexed from, address indexed to, uint256 value)"], + argKeys: { + to: "to", + from: "from", + amount: "value", + }, + isDeposit: false, +}; + +const ethDepositEventParams: ContractEventParams = { + target: null, + topic: "ReceivedEth(address, uint256, bytes32)", + abi: [ + "event ReceivedEth(address indexed from, uint256 value, bytes32 indexed principal)", + ], + argKeys: { + from: "from", + amount: "value", + to: 'principal' + }, + isDeposit: true, +}; + +const nativeTokenTransferSignature = ["0x535741", "0x"]; + + +function constructParams(chain: string) { + return async (fromBlock: number, toBlock: number) => { + const eventParams: PartialContractEventParams[] = []; + + let ercContracts = await get_erc2Contracts(); + for (let i = 0; i < ercContracts.length; i++) { + const ercContract = ercContracts[i]; + // Erc20 deposits to the Erc20 helper contract + const ercDepositParams = { + ...ercDepositEventParams, + target: erc20_helper_contract, + } + // Erc20 withdrawals through the Erc20 token contract + const ercWithdrawParams = { + ...ercWithdrawalEventParams, + target: ercContract, + fixedEventData: { + from: eth_minter_address, + } + } + eventParams.push(ercDepositParams, ercWithdrawParams); + } + + // Eth deposits to the Ethereum helper contract + eventParams.push({ + ...ethDepositEventParams, + target: eth_helper_contract, + }); + + let eventLogData = await getTxDataFromEVMEventLogs("chain-fusion", chain, fromBlock, toBlock, eventParams); + + // Eth withdrawals through native Eth transactions + const nativeEvents = await Promise.all( + (await getTxsBlockRangeEtherscan(chain, eth_minter_address, fromBlock, toBlock, { + includeSignatures: nativeTokenTransferSignature, + // Withdrawals are Eth native transfers where the from address is the minter + })).filter((tx:any) => {tx.from == eth_minter_address}).map((tx: any) => { + const event: EventData = { + txHash: tx.hash, + blockNumber: +tx.blockNumber, + from: tx.from, + to: tx.to, + token: weth_contract_addresss, + amount: tx.value, + isDeposit: false, + }; + return event; + }) + ); + const allEvents = [...eventLogData, ...nativeEvents.flat()]; + return allEvents; +}; +} + + +const adapter: BridgeAdapter = { + ethereum: constructParams("ethereum"), +}; + +export default adapter; \ No newline at end of file From 60eaa362b7846bdf1ac071e72cd7cd0682a1b41d Mon Sep 17 00:00:00 2001 From: Nikolas Haimerl Date: Mon, 23 Sep 2024 10:06:19 +0000 Subject: [PATCH 2/4] add config --- package-lock.json | 2 +- package.json | 2 +- src/data/bridgeNetworkData.ts | 13 +++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5494e41b..31d80571 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "@defillama/sdk": "^5.0.54", "@solana/web3.js": "^1.87.3", "async-retry": "^1.3.1", - "axios": "^0.21.0", + "axios": "^0.21.4", "axios-rate-limit": "^1.3.0", "bignumber.js": "^9.0.1", "dotenv": "^8.2.0", diff --git a/package.json b/package.json index 9e7c160f..61ace497 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@defillama/sdk": "^5.0.54", "@solana/web3.js": "^1.87.3", "async-retry": "^1.3.1", - "axios": "^0.21.0", + "axios": "^0.21.4", "axios-rate-limit": "^1.3.0", "bignumber.js": "^9.0.1", "dotenv": "^8.2.0", diff --git a/src/data/bridgeNetworkData.ts b/src/data/bridgeNetworkData.ts index d962c894..b75fcd55 100644 --- a/src/data/bridgeNetworkData.ts +++ b/src/data/bridgeNetworkData.ts @@ -1005,4 +1005,17 @@ export default [ "x layer": "xlayer", }, }, + { + id: 63, + displayName: "Chain-Fusion", + bridgeDbName: "chain-fusion", + iconLink: "icons:chain-fusion", + largeTxThreshold: 10000, + url: "https://owlto.finance", + chains: [ + "Ethereum", + ], + chainMapping: { + }, + }, ] as BridgeNetwork[]; From c04ea39b22416f2f4c9c0a0549c5dd6518195244 Mon Sep 17 00:00:00 2001 From: Nikolas Haimerl Date: Mon, 23 Sep 2024 10:07:29 +0000 Subject: [PATCH 3/4] correct link --- src/data/bridgeNetworkData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/bridgeNetworkData.ts b/src/data/bridgeNetworkData.ts index b75fcd55..ffce9935 100644 --- a/src/data/bridgeNetworkData.ts +++ b/src/data/bridgeNetworkData.ts @@ -1011,7 +1011,7 @@ export default [ bridgeDbName: "chain-fusion", iconLink: "icons:chain-fusion", largeTxThreshold: 10000, - url: "https://owlto.finance", + url: "https://dashboard.internetcomputer.org/", chains: [ "Ethereum", ], From 3b44bbc070f52560b0f4bcf1a5c007a89b1a3dce Mon Sep 17 00:00:00 2001 From: Nikolas Haimerl Date: Tue, 24 Sep 2024 12:45:49 +0000 Subject: [PATCH 4/4] add adapter to index --- src/adapters/chain-fusion/index.ts | 8 ++++++-- src/adapters/index.ts | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/adapters/chain-fusion/index.ts b/src/adapters/chain-fusion/index.ts index a08d2a98..1de999dc 100644 --- a/src/adapters/chain-fusion/index.ts +++ b/src/adapters/chain-fusion/index.ts @@ -86,15 +86,19 @@ function constructParams(chain: string) { target: erc20_helper_contract, } // Erc20 withdrawals through the Erc20 token contract - const ercWithdrawParams = { + let ercWithdrawParams = { ...ercWithdrawalEventParams, target: ercContract, fixedEventData: { from: eth_minter_address, } } + // We set the token address for the erc20 withdrawal event + if (ercWithdrawParams.argKeys) { + ercWithdrawParams.argKeys.token = ercContract; + } eventParams.push(ercDepositParams, ercWithdrawParams); - } + } // Eth deposits to the Ethereum helper contract eventParams.push({ diff --git a/src/adapters/index.ts b/src/adapters/index.ts index 5c967eb1..9a857910 100644 --- a/src/adapters/index.ts +++ b/src/adapters/index.ts @@ -67,6 +67,7 @@ import minibridge from "./minibridge"; import cometbridge from "./cometbridge"; import fastbtc from "./rootstock-fastbtc-bridge" import crowdswap from "./crowdswap" +import chainfusion from "./chain-fusion" export default { polygon, @@ -137,6 +138,7 @@ export default { cometbridge, fastbtc, crowdswap, + chainfusion } as { [bridge: string]: BridgeAdapter; };