From c56d71223478fb85c6dcc9287c3dedc239ee7ea0 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Sep 2024 20:49:01 -0300 Subject: [PATCH 1/9] tx dispatcher for relaying transfer on ethereum and sepolia Notes: 1. Requires subgraph redeployment 2. Update state momentarily suspended fix: sanitizer when several transfers occur fix: headRequest when transferred profile is present --- next.config.js | 4 + src/app/[pohid]/CrossChain.tsx | 120 +- src/app/[pohid]/page.tsx | 15 +- src/components/Request/Grid.tsx | 7 +- .../abis/cross-chain-proof-of-humanity.ts | 1066 ++++++++--------- src/contracts/abis/ethereum-amb-bridge.ts | 5 + src/contracts/abis/gnosis-amb-helper.ts | 52 + src/contracts/abis/index.ts | 4 + src/contracts/hooks/useRelayRead.ts | 8 + src/contracts/hooks/useRelayWrite.ts | 8 + src/contracts/index.ts | 65 +- src/data/sanitizer.ts | 5 +- 12 files changed, 804 insertions(+), 555 deletions(-) create mode 100644 src/contracts/abis/ethereum-amb-bridge.ts create mode 100644 src/contracts/abis/gnosis-amb-helper.ts create mode 100644 src/contracts/hooks/useRelayRead.ts create mode 100644 src/contracts/hooks/useRelayWrite.ts diff --git a/next.config.js b/next.config.js index 8b44a17..7fba1bc 100644 --- a/next.config.js +++ b/next.config.js @@ -13,6 +13,10 @@ const nextConfig = { env: { REACT_APP_IPFS_GATEWAY: process.env.REACT_APP_IPFS_GATEWAY, DEPLOYED_APP: process.env.DEPLOYED_APP, + CHIADO_RPC: process.env.CHIADO_RPC, + SEPOLIA_RPC: process.env.SEPOLIA_RPC, + GNOSIS_RPC: process.env.GNOSIS_RPC, + MAINNET_RPC: process.env.MAINNET_RPC }, images: { remotePatterns: [ diff --git a/src/app/[pohid]/CrossChain.tsx b/src/app/[pohid]/CrossChain.tsx index 5132a17..b6d0b6e 100644 --- a/src/app/[pohid]/CrossChain.tsx +++ b/src/app/[pohid]/CrossChain.tsx @@ -7,19 +7,24 @@ import withClientConnected from "components/HighOrder/withClientConnected"; import { SupportedChain, SupportedChainId, + getChainRpc, supportedChains, } from "config/chains"; -import { Contract } from "contracts"; +import { Contract, CreationBlockNumber } from "contracts"; import useCCPoHWrite from "contracts/hooks/useCCPoHWrite"; import { HumanityQuery } from "generated/graphql"; import { timeAgo } from "utils/time"; -import { Address, Hash } from "viem"; -import { useAccount, useChainId } from "wagmi"; +import { Address, Hash, createPublicClient, http, toBytes, toHex } from "viem"; +import { mainnet, sepolia, useAccount, useChainId } from "wagmi"; import { useObservable } from "@legendapp/state/react"; import ChainLogo from "components/ChainLogo"; import { useLoading } from "hooks/useLoading"; import useWeb3Loaded from "hooks/useWeb3Loaded"; import { ContractData } from "data/contract"; +import useRelayWrite from "contracts/hooks/useRelayWrite"; +import gnosisAmbHelper from "contracts/abis/gnosis-amb-helper"; +import crossChainProofOfHumanity from "contracts/abis/cross-chain-proof-of-humanity"; +import { gnosisChiado } from "viem/chains"; interface CrossChainProps extends JSX.IntrinsicAttributes { contractData: Record; @@ -71,6 +76,7 @@ export default withClientConnected(function CrossChain({ [loading] ) ); + const [prepareUpdate] = useCCPoHWrite( "updateHumanity", useMemo( @@ -86,7 +92,22 @@ export default withClientConnected(function CrossChain({ ) ); - const transfer$ = useObservable({ + const [prepareRelayWrite] = useRelayWrite( + "executeSignatures", + useMemo( + () => ({ + onLoading() { + loading.start(); + }, + onReady(fire) { + fire(); + }, + }), + [loading] + ) + ); + + /* const transfer$ = useObservable({ transferHash: lastTransfer?.transferHash, foreignProxy: lastTransfer?.foreignProxy, transferTimestamp: lastTransfer?.transferTimestamp, @@ -103,6 +124,13 @@ export default withClientConnected(function CrossChain({ ), }); const transferState = transfer$.use(); + */ + + const publicClient = lastTransferChain && createPublicClient({ + chain: supportedChains[lastTransferChain.id], + transport: http(getChainRpc(lastTransferChain.id)), + }); + return (
@@ -116,7 +144,7 @@ export default withClientConnected(function CrossChain({ {web3Loaded && address?.toLowerCase() === claimer && - homeChain.id === chainId && winningStatus !== "transferring" && ( + homeChain.id === chainId && (winningStatus !== "transferring" && winningStatus !== "transferred") && ( (function CrossChain({ )} - {web3Loaded && + {/* {web3Loaded && homeChain.id === chainId && winningStatus === "transferring"? (function CrossChain({ // User will cancel this transfer if updates from sending chain null : null - } - {transferState.receivingChain && !(transferState.received) && ( + } */} + {/* {transferState.receivingChain && !(transferState.received) && ( @@ -238,6 +266,82 @@ export default withClientConnected(function CrossChain({
+ )} */} + {web3Loaded && + //address?.toLowerCase() === claimer && + //homeChain?.id === chainId && + homeChain && + winningStatus === 'transferred' && publicClient && ( + + ⏳ Pending relay + + } + header="Last transfer" + > +
+ + {lastTransferChain?.name} ▶{" "} + {homeChain?.name} + + + Received: {String(false)} + + Transfer hash: {lastTransfer?.transferHash?.substring(0, 12)}... + + {homeChain?.id === chainId && + (chainId === mainnet.id || chainId === sepolia.id) ? ( + + ) : (homeChain.id === mainnet.id || homeChain.id === sepolia.id)? ( +
+ + Connect to home chain for relaying the transferring profile + +
+ ) : ( +
+ + Relaying the transferring profile in this chain can take around 30 minutes + +
+ ) + } +
+
)} ); diff --git a/src/app/[pohid]/page.tsx b/src/app/[pohid]/page.tsx index 74f87ac..b8e7e59 100644 --- a/src/app/[pohid]/page.tsx +++ b/src/app/[pohid]/page.tsx @@ -1,7 +1,7 @@ import cn from "classnames"; import { HumanityQuery } from "generated/graphql"; import { shortenAddress } from "utils/address"; -import { explorerLink } from "config/chains"; +import { explorerLink, getForeignChain, idToChain } from "config/chains"; import { machinifyId, prettifyId } from "utils/identifier"; import { SupportedChainId, supportedChains } from "config/chains"; import Link from "next/link"; @@ -287,6 +287,19 @@ async function Profile({ params: { pohid } }: PageProps) { winningStatus={winnerClaimData.status} /> + ) : (pastRequests.length > 0 && pastRequests[0].status.id === 'transferred') ? ( + ) : ( <> Not claimed diff --git a/src/components/Request/Grid.tsx b/src/components/Request/Grid.tsx index 5ac1ce8..fb28ed1 100644 --- a/src/components/Request/Grid.tsx +++ b/src/components/Request/Grid.tsx @@ -77,9 +77,10 @@ const sortRequests = (request: RequestInterface[]): RequestInterface[] => { val, (req) => req!.status.id === "transferred" ); - for (let i = 0; i < iTransfArr.length; i++) { + //for (let i = 0; i < iTransfArr.length; i++) { + let i = 0; if (iTransfArr[i] >= 0) { - let iReceived = iTransfArr[i] + 1; + let iReceived = iTransfArr[i] + 2; // A transferred request is set to transferred after the receiving request is created, so we need to swap their order if (val[iReceived]) [val[iTransfArr[i]], val[iReceived]] = [ @@ -87,7 +88,7 @@ const sortRequests = (request: RequestInterface[]): RequestInterface[] => { val[iTransfArr[i]], ]; } - } + //} }); let requestsOut: RequestInterface[] = new Array(); pohIdGrouped.forEach((val, key) => { diff --git a/src/contracts/abis/cross-chain-proof-of-humanity.ts b/src/contracts/abis/cross-chain-proof-of-humanity.ts index 90bdbe6..3ea7a2c 100644 --- a/src/contracts/abis/cross-chain-proof-of-humanity.ts +++ b/src/contracts/abis/cross-chain-proof-of-humanity.ts @@ -1,596 +1,584 @@ export default [ { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "bridgeGateway", - type: "address", - }, - { - indexed: false, - internalType: "address", - name: "foreignProxy", - type: "address", - }, - ], - name: "GatewayAdded", - type: "event", + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "bridgeGateway", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "foreignProxy", + "type": "address" + } + ], + "name": "GatewayAdded", + "type": "event" }, { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "bridgeGateway", - type: "address", - }, - ], - name: "GatewayRemoved", - type: "event", + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "bridgeGateway", + "type": "address" + } + ], + "name": "GatewayRemoved", + "type": "event" }, { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes20", - name: "humanityId", - type: "bytes20", - }, - { - indexed: true, - internalType: "address", - name: "owner", - type: "address", - }, - { - indexed: false, - internalType: "uint160", - name: "expirationTime", - type: "uint160", - }, - { - indexed: false, - internalType: "address", - name: "gateway", - type: "address", - }, - { - indexed: false, - internalType: "bytes32", - name: "transferHash", - type: "bytes32", - }, - ], - name: "TransferInitiated", - type: "event", + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes20", + "name": "humanityId", + "type": "bytes20" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint40", + "name": "expirationTime", + "type": "uint40" + }, + { + "indexed": false, + "internalType": "address", + "name": "gateway", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "transferHash", + "type": "bytes32" + } + ], + "name": "TransferInitiated", + "type": "event" }, { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes20", - name: "humanityId", - type: "bytes20", - }, - { - indexed: true, - internalType: "address", - name: "owner", - type: "address", - }, - { - indexed: false, - internalType: "uint160", - name: "expirationTime", - type: "uint160", - }, - { - indexed: false, - internalType: "bytes32", - name: "transferHash", - type: "bytes32", - }, - ], - name: "TransferReceived", - type: "event", + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes20", + "name": "humanityId", + "type": "bytes20" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint40", + "name": "expirationTime", + "type": "uint40" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "transferHash", + "type": "bytes32" + } + ], + "name": "TransferReceived", + "type": "event" }, { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "bytes32", - name: "transferHash", - type: "bytes32", - }, - ], - name: "TransferRetry", - type: "event", + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes20", + "name": "humanityId", + "type": "bytes20" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint40", + "name": "expirationTime", + "type": "uint40" + }, + { + "indexed": false, + "internalType": "bool", + "name": "claimed", + "type": "bool" + }, + { + "indexed": false, + "internalType": "address", + "name": "gateway", + "type": "address" + } + ], + "name": "UpdateInitiated", + "type": "event" }, { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes20", - name: "humanityId", - type: "bytes20", - }, - { - indexed: true, - internalType: "address", - name: "owner", - type: "address", - }, - { - indexed: false, - internalType: "uint160", - name: "expirationTime", - type: "uint160", - }, - { - indexed: false, - internalType: "address", - name: "gateway", - type: "address", - }, - { - indexed: false, - internalType: "bool", - name: "claimed", - type: "bool", - }, - ], - name: "UpdateInitiated", - type: "event", + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes20", + "name": "humanityId", + "type": "bytes20" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint40", + "name": "expirationTime", + "type": "uint40" + }, + { + "indexed": false, + "internalType": "bool", + "name": "claimed", + "type": "bool" + } + ], + "name": "UpdateReceived", + "type": "event" }, { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "bytes20", - name: "humanityId", - type: "bytes20", - }, - { - indexed: true, - internalType: "address", - name: "owner", - type: "address", - }, - { - indexed: false, - internalType: "uint160", - name: "expirationTime", - type: "uint160", - }, - { - indexed: false, - internalType: "bool", - name: "claimed", - type: "bool", - }, - ], - name: "UpdateReceived", - type: "event", + "inputs": [ + { + "internalType": "address", + "name": "_bridgeGateway", + "type": "address" + }, + { + "internalType": "address", + "name": "_foreignProxy", + "type": "address" + } + ], + "name": "addBridgeGateway", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "_bridgeGateway", - type: "address", - }, - { - internalType: "address", - name: "_foreignProxy", - type: "address", - }, - ], - name: "addBridgeGateway", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "bytes20", + "name": "_humanityId", + "type": "bytes20" + } + ], + "name": "boundTo", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], - name: "bridgeGateways", - outputs: [ - { - internalType: "address", - name: "foreignProxy", - type: "address", - }, - { - internalType: "bool", - name: "approved", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "bridgeGateways", + "outputs": [ + { + "internalType": "address", + "name": "foreignProxy", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "_governor", - type: "address", - }, - ], - name: "changeGovernor", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "address", + "name": "_governor", + "type": "address" + } + ], + "name": "changeGovernor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [ - { - internalType: "contract IProofOfHumanity", - name: "_proofOfHumanity", - type: "address", - }, - ], - name: "changeProofOfHumanity", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "contract IProofOfHumanity", + "name": "_proofOfHumanity", + "type": "address" + } + ], + "name": "changeProofOfHumanity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [], - name: "governor", - outputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "bytes20", - name: "", - type: "bytes20", - }, - ], - name: "humanityMapping", - outputs: [ - { - internalType: "bool", - name: "isHomeChain", - type: "bool", - }, - { - internalType: "uint40", - name: "expirationTime", - type: "uint40", - }, - { - internalType: "address", - name: "owner", - type: "address", - }, - { - internalType: "uint40", - name: "lastTransferTime", - type: "uint40", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [ + { + "internalType": "bytes20", + "name": "", + "type": "bytes20" + } + ], + "name": "humanityData", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint40", + "name": "expirationTime", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "lastTransferTime", + "type": "uint40" + }, + { + "internalType": "bool", + "name": "isHomeChain", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], - name: "humans", - outputs: [ - { - internalType: "bytes20", - name: "", - type: "bytes20", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "humanityOf", + "outputs": [ + { + "internalType": "bytes20", + "name": "humanityId", + "type": "bytes20" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "contract IProofOfHumanity", - name: "_proofOfHumanity", - type: "address", - }, - { - internalType: "uint256", - name: "_transferCooldown", - type: "uint256", - }, - ], - name: "initialize", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "contract IProofOfHumanity", + "name": "_proofOfHumanity", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_transferCooldown", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [], - name: "initialized", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [], + "name": "initialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "bytes20", - name: "_humanityId", - type: "bytes20", - }, - ], - name: "isClaimed", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [ + { + "internalType": "bytes20", + "name": "_humanityId", + "type": "bytes20" + } + ], + "name": "isClaimed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "_owner", - type: "address", - }, - ], - name: "isHuman", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "isHuman", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [], - name: "proofOfHumanity", - outputs: [ - { - internalType: "contract IProofOfHumanity", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [], + "name": "proofOfHumanity", + "outputs": [ + { + "internalType": "contract IProofOfHumanity", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "_owner", - type: "address", - }, - { - internalType: "bytes20", - name: "_humanityId", - type: "bytes20", - }, - { - internalType: "uint64", - name: "_expirationTime", - type: "uint64", - }, - { - internalType: "bytes32", - name: "_transferHash", - type: "bytes32", - }, - ], - name: "receiveTransfer", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "bytes20", + "name": "_humanityId", + "type": "bytes20" + }, + { + "internalType": "uint40", + "name": "_expirationTime", + "type": "uint40" + }, + { + "internalType": "bytes32", + "name": "_transferHash", + "type": "bytes32" + } + ], + "name": "receiveTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "_owner", - type: "address", - }, - { - internalType: "bytes20", - name: "_humanityId", - type: "bytes20", - }, - { - internalType: "uint64", - name: "_expirationTime", - type: "uint64", - }, - { - internalType: "bool", - name: "_isActive", - type: "bool", - }, - ], - name: "receiveUpdate", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "bytes20", + "name": "_humanityId", + "type": "bytes20" + }, + { + "internalType": "uint40", + "name": "_expirationTime", + "type": "uint40" + }, + { + "internalType": "bool", + "name": "_isActive", + "type": "bool" + } + ], + "name": "receiveUpdate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - name: "receivedTransferHashes", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "receivedTransferHashes", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "_bridgeGateway", - type: "address", - }, - ], - name: "removeBridgeGateway", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "address", + "name": "_bridgeGateway", + "type": "address" + } + ], + "name": "removeBridgeGateway", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [ - { - internalType: "bytes20", - name: "_humanityId", - type: "bytes20", - }, - { - internalType: "address", - name: "_bridgeGateway", - type: "address", - }, - ], - name: "retryFailedTransfer", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "uint256", + "name": "_transferCooldown", + "type": "uint256" + } + ], + "name": "setTransferCooldown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [ - { - internalType: "uint256", - name: "_transferCooldown", - type: "uint256", - }, - ], - name: "setTransferCooldown", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [], + "name": "transferCooldown", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [], - name: "transferCooldown", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", + "inputs": [ + { + "internalType": "address", + "name": "_bridgeGateway", + "type": "address" + } + ], + "name": "transferHumanity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - inputs: [ - { - internalType: "address", - name: "_bridgeGateway", - type: "address", - }, - ], - name: "transferHumanity", - outputs: [], - stateMutability: "nonpayable", - type: "function", + "inputs": [ + { + "internalType": "bytes20", + "name": "", + "type": "bytes20" + } + ], + "name": "transfers", + "outputs": [ + { + "internalType": "bytes20", + "name": "humanityId", + "type": "bytes20" + }, + { + "internalType": "uint40", + "name": "humanityExpirationTime", + "type": "uint40" + }, + { + "internalType": "bytes32", + "name": "transferHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "foreignProxy", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" }, { - inputs: [ - { - internalType: "bytes20", - name: "", - type: "bytes20", - }, - ], - name: "transfers", - outputs: [ - { - internalType: "bytes20", - name: "humanityId", - type: "bytes20", - }, - { - internalType: "uint64", - name: "humanityExpirationTime", - type: "uint64", - }, - { - internalType: "bytes32", - name: "transferHash", - type: "bytes32", - }, - { - internalType: "address", - name: "foreignProxy", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "_bridgeGateway", - type: "address", - }, - { - internalType: "bytes20", - name: "_humanityId", - type: "bytes20", - }, - ], - name: "updateHumanity", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, + "inputs": [ + { + "internalType": "address", + "name": "_bridgeGateway", + "type": "address" + }, + { + "internalType": "bytes20", + "name": "_humanityId", + "type": "bytes20" + } + ], + "name": "updateHumanity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } ] as const; diff --git a/src/contracts/abis/ethereum-amb-bridge.ts b/src/contracts/abis/ethereum-amb-bridge.ts new file mode 100644 index 0000000..4c8d49d --- /dev/null +++ b/src/contracts/abis/ethereum-amb-bridge.ts @@ -0,0 +1,5 @@ +export default [ + { + "constant":true,"inputs":[],"name":"transactionHash","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"sourceChainId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_txHash","type":"bytes32"}],"name":"relayedMessages","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_data","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"safeExecuteSignaturesWithAutoGasLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_sourceChainId","type":"uint256"},{"name":"_destinationChainId","type":"uint256"},{"name":"_validatorContract","type":"address"},{"name":"_maxGasPerTx","type":"uint256"},{"name":"_gasPrice","type":"uint256"},{"name":"_requiredBlockConfirmations","type":"uint256"},{"name":"_owner","type":"address"}],"name":"initialize","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"requiredBlockConfirmations","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_data","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"executeSignatures","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_messageId","type":"bytes32"}],"name":"failedMessageReceiver","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBridgeMode","outputs":[{"name":"_data","type":"bytes4"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_sourceChainId","type":"uint256"},{"name":"_destinationChainId","type":"uint256"}],"name":"setChainIds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_messageId","type":"bytes32"}],"name":"failedMessageSender","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allowReentrantRequests","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"messageId","outputs":[{"name":"id","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_to","type":"address"}],"name":"claimTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxGasPerTx","type":"uint256"}],"name":"setMaxGasPerTx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"requiredSignatures","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validatorContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deployedAtBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBridgeInterfacesVersion","outputs":[{"name":"major","type":"uint64"},{"name":"minor","type":"uint64"},{"name":"patch","type":"uint64"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"messageSourceChainId","outputs":[{"name":"id","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_blockConfirmations","type":"uint256"}],"name":"setRequiredBlockConfirmations","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"destinationChainId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_gasPrice","type":"uint256"}],"name":"setGasPrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_enable","type":"bool"}],"name":"setAllowReentrantRequests","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_messageId","type":"bytes32"}],"name":"messageCallStatus","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"messageSender","outputs":[{"name":"sender","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimalShift","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_contract","type":"address"},{"name":"_data","type":"bytes"},{"name":"_gas","type":"uint256"}],"name":"requireToPassMessage","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_messageId","type":"bytes32"}],"name":"failedMessageDataHash","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxGasPerTx","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_data","type":"bytes"},{"name":"_signatures","type":"bytes"},{"name":"_gas","type":"uint32"}],"name":"safeExecuteSignaturesWithGasLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_data","type":"bytes"},{"name":"_signatures","type":"bytes"}],"name":"safeExecuteSignatures","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"gasPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"messageId","type":"bytes32"},{"indexed":false,"name":"encodedData","type":"bytes"}],"name":"UserRequestForAffirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"executor","type":"address"},{"indexed":true,"name":"messageId","type":"bytes32"},{"indexed":false,"name":"status","type":"bool"}],"name":"RelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"gasPrice","type":"uint256"}],"name":"GasPriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"requiredBlockConfirmations","type":"uint256"}],"name":"RequiredBlockConfirmationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"previousOwner","type":"address"},{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event" + } +] as const; \ No newline at end of file diff --git a/src/contracts/abis/gnosis-amb-helper.ts b/src/contracts/abis/gnosis-amb-helper.ts new file mode 100644 index 0000000..e281968 --- /dev/null +++ b/src/contracts/abis/gnosis-amb-helper.ts @@ -0,0 +1,52 @@ +export default [ + { + "inputs": [ + { + "internalType": "address", + "name": "_homeBridge", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AMBcontract", + "outputs": [ + { + "internalType": "contract IHomeBridge", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "clean", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_message", + "type": "bytes" + } + ], + "name": "getSignatures", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + } +] as const; \ No newline at end of file diff --git a/src/contracts/abis/index.ts b/src/contracts/abis/index.ts index 9e00350..79a7d8c 100644 --- a/src/contracts/abis/index.ts +++ b/src/contracts/abis/index.ts @@ -2,11 +2,15 @@ import multicall3 from "./multicall3"; import klerosLiquid from "./kleros-liquid"; import crossChainProofOfHumanity from "./cross-chain-proof-of-humanity"; import proofOfHumanity from "./proof-of-humanity"; +import gnosisAMBHelper from "./gnosis-amb-helper"; +import ethereumAMBBridge from "./ethereum-amb-bridge"; const abis = { ProofOfHumanity: proofOfHumanity, KlerosLiquid: klerosLiquid, CrossChainProofOfHumanity: crossChainProofOfHumanity, + GnosisAMBHelper: gnosisAMBHelper, + EthereumAMBBridge: ethereumAMBBridge, // CirclesHub: ProofOfHumanityAbi, // PoHGroupCurrencyManager: ProofOfHumanityAbi, // GroupCurrencyToken: ProofOfHumanityAbi, diff --git a/src/contracts/hooks/useRelayRead.ts b/src/contracts/hooks/useRelayRead.ts new file mode 100644 index 0000000..bfddec4 --- /dev/null +++ b/src/contracts/hooks/useRelayRead.ts @@ -0,0 +1,8 @@ +import useWagmiRead from "./useWagmiRead"; +import { ReadArgs, ReadFunctionName } from "./types"; + +export default function useRelayRead< + F extends ReadFunctionName<"GnosisAMBHelper"> +>(functionName: F, args?: ReadArgs<"GnosisAMBHelper", F>) { + return useWagmiRead("GnosisAMBHelper", functionName, args); +} diff --git a/src/contracts/hooks/useRelayWrite.ts b/src/contracts/hooks/useRelayWrite.ts new file mode 100644 index 0000000..8547580 --- /dev/null +++ b/src/contracts/hooks/useRelayWrite.ts @@ -0,0 +1,8 @@ +import useWagmiWrite from "./useWagmiWrite"; +import { Effects, WriteFunctionName } from "./types"; + +export default function useRelayWrite< + F extends WriteFunctionName<"EthereumAMBBridge"> +>(functionName: F, effects?: Effects) { + return useWagmiWrite("EthereumAMBBridge", functionName, effects); +} diff --git a/src/contracts/index.ts b/src/contracts/index.ts index e073411..62982ec 100644 --- a/src/contracts/index.ts +++ b/src/contracts/index.ts @@ -13,7 +13,9 @@ export const configSets = { 'mainPreAudit': {chainSet: ChainSet.MAINNETS, chainSetId: 'mainPreAudit', id: '5'}, }; -export const configSetSelection = process.env.DEPLOYED_APP == 'https://testnets--proof-of-humanity-v2.netlify.app/'? configSets.testOld : configSets.main; +//export const configSetSelection = process.env.DEPLOYED_APP == 'https://testnets--proof-of-humanity-v2.netlify.app/'? configSets.testOld : configSets.main; +//export const configSetSelection = configSets.testNew; +export const configSetSelection = configSets.mainOld; export const Contract = { ProofOfHumanity: @@ -53,19 +55,78 @@ export const Contract = { } : (configSetSelection.id === configSets.main.id)? { [gnosis.id]: "0x16044E1063C08670f8653055A786b7CC2034d2b0", [mainnet.id]: "0xa478095886659168E8812154fB0DE39F103E74b2", + [sepolia.id]: "0x", + [gnosisChiado.id]: "0x", } : (configSetSelection.id === configSets.mainPreAudit.id)? { [gnosis.id]: "0xF921b42B541bc53a07067B65207F879c9377bf7F", [mainnet.id]: "0xD8D462ac9F3FAD77Af2ae2640fE7F591F1651A2C", + [sepolia.id]: "0x", + [gnosisChiado.id]: "0x", } : (configSetSelection.id === configSets.mainOld.id)? { [gnosis.id]: "0x6cbEdC1920090EA4F28A38C1CD61c8D37b2cc323", [mainnet.id]: "0xD6F4E9d906CD7736a83e0AFa7EE9491658B4afA7", - } : {}, + [sepolia.id]: "0x", + [gnosisChiado.id]: "0x", + } : { + [mainnet.id]: "0x", + [gnosis.id]: "0x", + [sepolia.id]: "0x", + [gnosisChiado.id]: "0x", + }, Multicall3: { [mainnet.id]: mainnet.contracts.multicall3.address, [sepolia.id]: sepolia.contracts.multicall3.address, [gnosis.id]: gnosis.contracts.multicall3.address, [gnosisChiado.id]: gnosisChiado.contracts.multicall3.address, }, + GnosisAMBHelper: { + [mainnet.id]: "0x", + [sepolia.id]: "0x", + [gnosis.id]: "0x7d94ece17e81355326e3359115D4B02411825EdD", + [gnosisChiado.id]: "0x3cc500B3c01D04C265c9293cB35BA2Fd8eA6dc1b", + }, + EthereumAMBBridge: { + [mainnet.id]: "0x4C36d2919e407f0Cc2Ee3c993ccF8ac26d9CE64e", + [sepolia.id]: "0xf2546D6648BD2af6a008A7e7C1542BB240329E11", + [gnosis.id]: "0x", + [gnosisChiado.id]: "0x", + }, } as const; +export const CreationBlockNumber = { + CrossChainProofOfHumanity: + (configSetSelection.id === configSets.testOld.id) ? + { + [mainnet.id]: 0, //OLD + [sepolia.id]: 0, //OLD + [gnosisChiado.id]: BigInt(8944663), //OLD + [gnosis.id]: 0, + } : (configSetSelection.id === configSets.testNew.id)? { + [gnosis.id]: 0, + [mainnet.id]: 0, + [sepolia.id]: 0, + [gnosisChiado.id]: BigInt(10533290), + } : (configSetSelection.id === configSets.main.id)? { + [gnosis.id]: BigInt(35846905), + [mainnet.id]: 0, + [sepolia.id]: 0, + [gnosisChiado.id]: 0, + } : (configSetSelection.id === configSets.mainPreAudit.id)? { + [gnosis.id]: BigInt(35610817), + [mainnet.id]: 0, + [sepolia.id]: 0, + [gnosisChiado.id]: 0, + } : (configSetSelection.id === configSets.mainOld.id)? { + [gnosis.id]: BigInt(34761332), + [mainnet.id]: 0, + [sepolia.id]: 0, + [gnosisChiado.id]: 0, + } : { + [mainnet.id]: 0, + [gnosis.id]: 0, + [sepolia.id]: 0, + [gnosisChiado.id]: 0, + }, +} + export type ContractName = keyof typeof Contract; diff --git a/src/data/sanitizer.ts b/src/data/sanitizer.ts index bd67655..fc22232 100644 --- a/src/data/sanitizer.ts +++ b/src/data/sanitizer.ts @@ -230,12 +230,12 @@ export const sanitizeHeadRequests = async ( var transferringRequest; if (foreignChainId && all[foreignChainId].length>0 && (Number(req.index) <= -100 || (Number(req.index) >= 0 && req.revocation))) { transferringRequest = all[foreignChainId] - .filter(req => (req.humanity.id === pohId && (req.status.id == "transferred")))// || req.status.id == "transferring"))) + .filter(req => (req.humanity.id === pohId && (req.status.id == "transferred") && !!req.evidenceGroup.evidence.at(0)))// || req.status.id == "transferring"))) .sort((req1, req2) => req2.creationTime - req1.creationTime) .at(0); if (!(!!transferringRequest?.evidenceGroup.evidence.at(0))) { transferringRequest = all[chain.id] - .filter(req => (req.humanity.id === pohId && (req.status.id == "transferred")))// || req.status.id == "transferring"))) + .filter(req => (req.humanity.id === pohId && (req.status.id == "transferred" && !!req.evidenceGroup.evidence.at(0))))// || req.status.id == "transferring"))) .sort((req1, req2) => req2.creationTime - req1.creationTime) .at(0); } @@ -262,6 +262,7 @@ export const sanitizeHeadRequests = async ( transferringRequest = (await getRequestDataReduced(chain.id, pohId, -1)); } } */ + console.log("TRANSFFF>>>> ", transferringRequest) req.claimer.name = transferringRequest?.claimer.name; if (req.revocation) { if (req.registrationEvidenceRevokedReq == "" && transferringRequest) { From 8e41f93af81ea189ea65c8d74fdeb810eb4486ab Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 18 Sep 2024 21:31:21 -0300 Subject: [PATCH 2/9] catch: manual relay needs to wait for confirmation --- src/app/[pohid]/CrossChain.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/app/[pohid]/CrossChain.tsx b/src/app/[pohid]/CrossChain.tsx index b6d0b6e..de03f22 100644 --- a/src/app/[pohid]/CrossChain.tsx +++ b/src/app/[pohid]/CrossChain.tsx @@ -25,6 +25,7 @@ import useRelayWrite from "contracts/hooks/useRelayWrite"; import gnosisAmbHelper from "contracts/abis/gnosis-amb-helper"; import crossChainProofOfHumanity from "contracts/abis/cross-chain-proof-of-humanity"; import { gnosisChiado } from "viem/chains"; +import { toast } from "react-toastify"; interface CrossChainProps extends JSX.IntrinsicAttributes { contractData: Record; @@ -312,15 +313,19 @@ export default withClientConnected(function CrossChain({ const subEnd = lastTransferChain.id === gnosisChiado.id? 754 : 748; const encodedData = `0x${data?.substring(130, subEnd)}` as `0x${string}`; - const signatures = await publicClient.readContract({ + await publicClient.readContract({ address: Contract.GnosisAMBHelper[lastTransferChain.id], abi: gnosisAmbHelper, functionName: 'getSignatures', args: [encodedData] - }); - - prepareRelayWrite({ - args: [encodedData, signatures], + }) + .then((signatures)=> { + prepareRelayWrite({ + args: [encodedData, signatures], + }); + }) + .catch(e => { + toast.info("Confirmation takes around 10 minutes. Come back later"); }); }} > From d2961315bc659f05925b8d45711b4aabef172e20 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 19 Sep 2024 18:34:58 -0300 Subject: [PATCH 3/9] update state and controls for execute its relayer tx --- src/app/[pohid]/CrossChain.tsx | 210 ++++++++++++++++++++++---------- src/app/[pohid]/page.tsx | 22 +--- src/components/Request/Grid.tsx | 32 ----- src/contracts/index.ts | 21 ++-- src/data/sanitizer.ts | 1 - 5 files changed, 158 insertions(+), 128 deletions(-) diff --git a/src/app/[pohid]/CrossChain.tsx b/src/app/[pohid]/CrossChain.tsx index de03f22..3fad8b1 100644 --- a/src/app/[pohid]/CrossChain.tsx +++ b/src/app/[pohid]/CrossChain.tsx @@ -1,6 +1,6 @@ "use client"; -import { useMemo } from "react"; +import { useEffect, useMemo, useState } from "react"; import Modal from "components/Modal"; import TimeAgo from "components/TimeAgo"; import withClientConnected from "components/HighOrder/withClientConnected"; @@ -8,15 +8,16 @@ import { SupportedChain, SupportedChainId, getChainRpc, + getForeignChain, + idToChain, supportedChains, } from "config/chains"; import { Contract, CreationBlockNumber } from "contracts"; import useCCPoHWrite from "contracts/hooks/useCCPoHWrite"; import { HumanityQuery } from "generated/graphql"; import { timeAgo } from "utils/time"; -import { Address, Hash, createPublicClient, http, toBytes, toHex } from "viem"; +import { Address, Hash, createPublicClient, http } from "viem"; import { mainnet, sepolia, useAccount, useChainId } from "wagmi"; -import { useObservable } from "@legendapp/state/react"; import ChainLogo from "components/ChainLogo"; import { useLoading } from "hooks/useLoading"; import useWeb3Loaded from "hooks/useWeb3Loaded"; @@ -38,15 +39,6 @@ interface CrossChainProps extends JSX.IntrinsicAttributes { winningStatus?: string; } -type TransferType = { - transferHash: string, - foreignProxy: Address, - transferTimestamp: string, - senderChain: SupportedChain | undefined, - receivingChain: SupportedChain, - received: boolean, -} - export default withClientConnected(function CrossChain({ pohId, contractData, @@ -61,7 +53,7 @@ export default withClientConnected(function CrossChain({ const { address } = useAccount(); const loading = useLoading(); const web3Loaded = useWeb3Loaded(); - const chainId = useChainId(); + const chainId = useChainId() as SupportedChainId; const [prepareTransfer, doTransfer] = useCCPoHWrite( "transferHumanity", @@ -108,30 +100,141 @@ export default withClientConnected(function CrossChain({ ) ); - /* const transfer$ = useObservable({ - transferHash: lastTransfer?.transferHash, - foreignProxy: lastTransfer?.foreignProxy, - transferTimestamp: lastTransfer?.transferTimestamp, - senderChain: lastTransferChain, - receivingChain: supportedChains.find( - (chain) => - Contract.CrossChainProofOfHumanity[chain.id]?.toLowerCase() === - lastTransfer?.foreignProxy - )!, - received: !!supportedChains.find( - (c) => - Contract.CrossChainProofOfHumanity[c.id]?.toLowerCase() === - lastTransfer?.foreignProxy - ), - }); - const transferState = transfer$.use(); - */ + type RelayUpdateParams = { + sideChainId: 100|10200, + publicClientSide: any, + encodedData: `0x${string}` + }; + + const [pendingRelayUpdate, setPendingRelayUpdate] = useState({} as RelayUpdateParams); const publicClient = lastTransferChain && createPublicClient({ chain: supportedChains[lastTransferChain.id], transport: http(getChainRpc(lastTransferChain.id)), }); + + const pendingRelayUpdateEthereum = async () => { + if (web3Loaded && + //(chainId === mainnet.id || chainId === sepolia.id) && + (winningStatus !== "transferring" && winningStatus !== "transferred") + ) { + const sideChain = idToChain(getForeignChain(chainId)); + const sideChainId = sideChain!.id as 100|10200; + const publicClientSide = createPublicClient({ + chain: supportedChains[sideChainId], + transport: http(getChainRpc(sideChainId)), + }); + const address = Contract.CrossChainProofOfHumanity[sideChainId] as Address; + const allTxs = await publicClientSide.getContractEvents({ + address: address, + abi: crossChainProofOfHumanity, + eventName: 'UpdateInitiated', + fromBlock: CreationBlockNumber.CrossChainProofOfHumanity[sideChainId] as bigint, + strict: true, + args: {humanityId: pohId}, + }); + + if (allTxs.length == 0) return ; + + const txHash = allTxs && allTxs[0].transactionHash; + + const tx = await publicClientSide.getTransactionReceipt({hash: txHash}); + const messageId = tx.logs.at(0)?.topics.at(1); + + // Looking for the received update with same messageId, if there is no such tx, then it is pending + + const publicClientEthereum = createPublicClient({ + chain: supportedChains[chainId], + transport: http(getChainRpc(chainId)), + }); + const addressEthereum = Contract.CrossChainProofOfHumanity[chainId] as Address; + const allTxsEthereum = await publicClientEthereum.getContractEvents({ + address: addressEthereum, + abi: crossChainProofOfHumanity, + eventName: 'UpdateReceived', + fromBlock: CreationBlockNumber.CrossChainProofOfHumanity[chainId] as bigint, + strict: true, + args: {humanityId: pohId}, + }); + + var messageIdEthereum; + if (allTxsEthereum.length > 0) { + const txHashEthereum = allTxsEthereum[0].transactionHash; + + const txEthereum = await publicClientEthereum.getTransactionReceipt({hash: txHashEthereum}); + messageIdEthereum = txEthereum.logs.at(1)?.topics.at(3); + } + + if (allTxsEthereum.length == 0 || messageId !== messageIdEthereum) { + const data = (tx.logs.at(0)?.data); + + // Encoded data has a different length in Gnosis compared to Chiado + const subEnd = sideChainId === gnosisChiado.id? 754 : 748; + const encodedData = `0x${data?.substring(130, subEnd)}` as `0x${string}`; + + setPendingRelayUpdate({sideChainId: sideChainId, publicClientSide: publicClientSide, encodedData: encodedData}); + return ; + } + return ; + } + return ; + } + + const showPendingUpdate = () => { + return ( + + ⏳ Pending relay + + } + header="Last update" + > +
+ + There is a pending state update that needs to be relayed on this chain. + + {(pendingRelayUpdate.sideChainId === 100 || pendingRelayUpdate.sideChainId === 10200)? ( + + ) : ( +
+ + Relaying a state update in this chain can take around 30 minutes + +
+ )} +
+
+ ) + } + useEffect(()=>{ + if (web3Loaded && + //(chainId === mainnet.id || chainId === sepolia.id) && + (winningStatus !== "transferring" && winningStatus !== "transferred") + ) + pendingRelayUpdateEthereum() + }, [web3Loaded, chainId]); return (
@@ -170,8 +273,10 @@ export default withClientConnected(function CrossChain({ )} - {/* {web3Loaded && - homeChain.id === chainId && winningStatus === "transferring"? + {web3Loaded && + homeChain.id === chainId && + (winningStatus !== "transferring" && winningStatus !== "transferred") && + (!pendingRelayUpdate || !pendingRelayUpdate.encodedData) && ( (function CrossChain({
- : web3Loaded && - transferState.senderChain?.id === chainId && winningStatus === "transferring"? - // TODO !!!!!!!!!!!!!!!! - // User will cancel this transfer if updates from sending chain - null - : null - } */} - {/* {transferState.receivingChain && !(transferState.received) && ( - - ⏳ Pending transfer - - } - header="Last transfer" - > -
- - {transferState.senderChain?.name} ▶{" "} - {transferState.receivingChain?.name} - - - Received: {String(transferState.received)} - - Transfer hash: {transferState.transferHash?.substring(0, 12)}... - -
-
- )} */} + )} {web3Loaded && //address?.toLowerCase() === claimer && //homeChain?.id === chainId && @@ -287,10 +364,6 @@ export default withClientConnected(function CrossChain({ {homeChain?.name} - Received: {String(false)} - - Transfer hash: {lastTransfer?.transferHash?.substring(0, 12)}... - {homeChain?.id === chainId && (chainId === mainnet.id || chainId === sepolia.id) ? ( ) : !isVouchGranted.didIVouchFor ? ( - + ) : isVouchGranted.isVouchOnchain ? ( - + ) : null} @@ -354,9 +358,9 @@ export default withClientConnected(function ActionBar({ Withdraw ) : !isVouchGranted.didIVouchFor ? ( - + ) : isVouchGranted.isVouchOnchain ? ( - + ) : null}