Last active
April 16, 2025 11:00
-
-
Save zengzengzenghuy/42fce269a8282120d538208e62938f37 to your computer and use it in GitHub Desktop.
Given a xDAI relayTokens or Transfer transaction hash from Gnosis Chain, call executeSignature on Ethereum to claim DAI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { | |
| createPublicClient, | |
| createWalletClient, | |
| http, | |
| parseAbiItem, | |
| decodeEventLog, | |
| } from "viem"; | |
| import { privateKeyToAccount } from "viem/accounts"; | |
| import { gnosis, mainnet } from "viem/chains"; | |
| // Get input from CLI | |
| const [, , privateKey, txHash] = process.argv; | |
| if (!privateKey || !txHash) { | |
| console.error("Usage: node myScript.js <privateKey> <txHash>"); | |
| process.exit(1); | |
| } | |
| // === Set up Clients === | |
| const gnosisClient = createPublicClient({ chain: gnosis, transport: http() }); | |
| const ethereumClient = createPublicClient({ | |
| chain: mainnet, | |
| transport: http(), | |
| }); | |
| const account = privateKeyToAccount(privateKey); | |
| const walletClient = createWalletClient({ | |
| account, | |
| chain: mainnet, | |
| transport: http(), | |
| }); | |
| // === Step 1: Fetch UserRequestForSignature event from tx === | |
| const EVENT_SIGNATURE = | |
| "event UserRequestForSignature(address recipient, uint256 value, bytes32 nonce)"; | |
| async function main() { | |
| const receipt = await gnosisClient.getTransactionReceipt({ hash: txHash }); | |
| const userRequestLog = receipt.logs.find((log) => { | |
| try { | |
| const decoded = decodeEventLog({ | |
| abi: [parseAbiItem(EVENT_SIGNATURE)], | |
| data: log.data, | |
| topics: log.topics, | |
| }); | |
| return decoded.eventName === "UserRequestForSignature"; | |
| } catch (e) { | |
| return false; | |
| } | |
| }); | |
| if (!userRequestLog) { | |
| console.error("UserRequestForSignature event not found in transaction"); | |
| return; | |
| } | |
| const decoded = decodeEventLog({ | |
| abi: [parseAbiItem(EVENT_SIGNATURE)], | |
| data: userRequestLog.data, | |
| topics: userRequestLog.topics, | |
| }); | |
| const { recipient, value, nonce } = decoded.args; | |
| console.log("Extracted Event Data:", { recipient, value, nonce }); | |
| // === Step 2: Call getMessageHash === | |
| const bridgeAddress = "0x2d51eaa266eafcb59bb36dd3c7e99c515e58113a"; | |
| const msgHash = await gnosisClient.readContract({ | |
| address: bridgeAddress, | |
| abi: [ | |
| { | |
| name: "getMessageHash", | |
| type: "function", | |
| inputs: [ | |
| { name: "_recipient", type: "address" }, | |
| { name: "_value", type: "uint256" }, | |
| { name: "_origTxHash", type: "bytes32" }, | |
| ], | |
| outputs: [{ type: "bytes32" }], | |
| }, | |
| ], | |
| functionName: "getMessageHash", | |
| args: [recipient, value, nonce], | |
| }); | |
| console.log("Message Hash:", msgHash); | |
| // === Step 3: getMessage & getSignatures === | |
| const message = await gnosisClient.readContract({ | |
| address: bridgeAddress, | |
| abi: [ | |
| { | |
| name: "getMessage", | |
| type: "function", | |
| inputs: [{ name: "_msgHash", type: "bytes32" }], | |
| outputs: [{ type: "bytes" }], | |
| }, | |
| ], | |
| functionName: "getMessage", | |
| args: [msgHash], | |
| }); | |
| const signatures = await gnosisClient.readContract({ | |
| address: bridgeAddress, | |
| abi: [ | |
| { | |
| name: "getSignatures", | |
| type: "function", | |
| inputs: [{ name: "_msgHash", type: "bytes32" }], | |
| outputs: [{ type: "bytes" }], | |
| }, | |
| ], | |
| functionName: "getSignatures", | |
| args: [msgHash], | |
| }); | |
| if (signatures.length !== 524) { | |
| console.error("Not enough signatures from validators"); | |
| return; | |
| } | |
| console.log("Signatures validated."); | |
| // === Step 4: simulate executeSignatures on Ethereum === | |
| const ethereumBridgeAddress = "0x4aa42145Aa6Ebf72e164C9bBC74fbD3788045016"; | |
| try { | |
| const simulation = await ethereumClient.simulateContract({ | |
| address: ethereumBridgeAddress, | |
| abi: [ | |
| { | |
| name: "executeSignatures", | |
| type: "function", | |
| stateMutability: "nonpayable", | |
| inputs: [ | |
| { name: "message", type: "bytes" }, | |
| { name: "signatures", type: "bytes" }, | |
| ], | |
| outputs: [], | |
| }, | |
| ], | |
| functionName: "executeSignatures", | |
| args: [message, signatures], | |
| account, | |
| }); | |
| console.log( | |
| "Simulation successful, transaction request:", | |
| simulation.request | |
| ); | |
| // Optional: Send transaction | |
| const hash = await walletClient.writeContract(simulation.request); | |
| console.log("Transaction sent:", hash); | |
| } catch (err) { | |
| console.error("Simulation failed:", err.message); | |
| } | |
| } | |
| main(); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script simplify the process to collect signatures from xDAI Bridge Helper contract and claim DAI on Ethereum xDAI Bridge contract.
You would need the tx hash that calls
TransferorrelayTokensto the Gnosis Chain xDAI Bridge, and private key with enough ETH on Ethereum to claim DAI on Ethereum.node index.js $YourPrivateKey $OriginTxHashFromGnosisChainCheck here if you want to interact with block explorer.
Fund your account with ETH from other networks with https://www.gas.zip/