diff --git a/apps/web/src/config/abi/gelatoLimit.ts b/apps/web/src/config/abi/gelatoLimit.ts
new file mode 100644
index 0000000000000..f4d558bea482e
--- /dev/null
+++ b/apps/web/src/config/abi/gelatoLimit.ts
@@ -0,0 +1,363 @@
+export const gelatoLimitABI = [
+ {
+ inputs: [{ internalType: 'address', name: '_gelato', type: 'address' }],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'bytes32', name: '_key', type: 'bytes32' },
+ {
+ indexed: true,
+ internalType: 'address',
+ name: '_caller',
+ type: 'address',
+ },
+ { indexed: false, internalType: 'uint256', name: '_amount', type: 'uint256' },
+ {
+ indexed: false,
+ internalType: 'bytes',
+ name: '_data',
+ type: 'bytes',
+ },
+ ],
+ name: 'DepositETH',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'bytes32', name: '_key', type: 'bytes32' },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { indexed: false, internalType: 'address', name: '_owner', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { indexed: false, internalType: 'bytes', name: '_data', type: 'bytes' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: '_amount',
+ type: 'uint256',
+ },
+ ],
+ name: 'OrderCancelled',
+ type: 'event',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'bytes32', name: '_key', type: 'bytes32' },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { indexed: false, internalType: 'address', name: '_owner', type: 'address' },
+ {
+ indexed: false,
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { indexed: false, internalType: 'bytes', name: '_data', type: 'bytes' },
+ {
+ indexed: false,
+ internalType: 'bytes',
+ name: '_auxData',
+ type: 'bytes',
+ },
+ { indexed: false, internalType: 'uint256', name: '_amount', type: 'uint256' },
+ {
+ indexed: false,
+ internalType: 'uint256',
+ name: '_bought',
+ type: 'uint256',
+ },
+ ],
+ name: 'OrderExecuted',
+ type: 'event',
+ },
+ {
+ inputs: [],
+ name: 'ETH_ADDRESS',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [],
+ name: 'GELATO',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IModule',
+ name: '_module',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IERC20',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: '_owner', type: 'address' },
+ {
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { internalType: 'bytes', name: '_data', type: 'bytes' },
+ {
+ internalType: 'bytes',
+ name: '_auxData',
+ type: 'bytes',
+ },
+ ],
+ name: 'canExecuteOrder',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IModule',
+ name: '_module',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IERC20',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: '_owner', type: 'address' },
+ {
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { internalType: 'bytes', name: '_data', type: 'bytes' },
+ ],
+ name: 'cancelOrder',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes', name: '_data', type: 'bytes' }],
+ name: 'decodeOrder',
+ outputs: [
+ { internalType: 'address', name: 'module', type: 'address' },
+ {
+ internalType: 'address',
+ name: 'inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: 'owner', type: 'address' },
+ {
+ internalType: 'address',
+ name: 'witness',
+ type: 'address',
+ },
+ { internalType: 'bytes', name: 'data', type: 'bytes' },
+ {
+ internalType: 'bytes32',
+ name: 'secret',
+ type: 'bytes32',
+ },
+ ],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes', name: '_data', type: 'bytes' }],
+ name: 'depositEth',
+ outputs: [],
+ stateMutability: 'payable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_module', type: 'address' },
+ {
+ internalType: 'address',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: '_owner', type: 'address' },
+ {
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { internalType: 'bytes', name: '_data', type: 'bytes' },
+ {
+ internalType: 'bytes32',
+ name: '_secret',
+ type: 'bytes32',
+ },
+ ],
+ name: 'encodeEthOrder',
+ outputs: [{ internalType: 'bytes', name: '', type: 'bytes' }],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IModule',
+ name: '_module',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IERC20',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: '_owner', type: 'address' },
+ {
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { internalType: 'bytes', name: '_data', type: 'bytes' },
+ {
+ internalType: 'bytes32',
+ name: '_secret',
+ type: 'bytes32',
+ },
+ { internalType: 'uint256', name: '_amount', type: 'uint256' },
+ ],
+ name: 'encodeTokenOrder',
+ outputs: [{ internalType: 'bytes', name: '', type: 'bytes' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ name: 'ethDeposits',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IModule',
+ name: '_module',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IERC20',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: '_owner', type: 'address' },
+ {
+ internalType: 'bytes',
+ name: '_data',
+ type: 'bytes',
+ },
+ { internalType: 'bytes', name: '_signature', type: 'bytes' },
+ {
+ internalType: 'bytes',
+ name: '_auxData',
+ type: 'bytes',
+ },
+ ],
+ name: 'executeOrder',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IModule',
+ name: '_module',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IERC20',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: '_owner', type: 'address' },
+ {
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { internalType: 'bytes', name: '_data', type: 'bytes' },
+ ],
+ name: 'existOrder',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IModule',
+ name: '_module',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IERC20',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: '_owner', type: 'address' },
+ {
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { internalType: 'bytes', name: '_data', type: 'bytes' },
+ ],
+ name: 'keyOf',
+ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
+ stateMutability: 'pure',
+ type: 'function',
+ },
+ {
+ inputs: [
+ {
+ internalType: 'contract IModule',
+ name: '_module',
+ type: 'address',
+ },
+ {
+ internalType: 'contract IERC20',
+ name: '_inputToken',
+ type: 'address',
+ },
+ { internalType: 'address payable', name: '_owner', type: 'address' },
+ {
+ internalType: 'address',
+ name: '_witness',
+ type: 'address',
+ },
+ { internalType: 'bytes', name: '_data', type: 'bytes' },
+ ],
+ name: 'vaultOfOrder',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function',
+ },
+ { stateMutability: 'payable', type: 'receive' },
+]
diff --git a/apps/web/src/pages/api/query/transaction/index.ts b/apps/web/src/pages/api/query/transaction/index.ts
new file mode 100644
index 0000000000000..ded0a2056e6f7
--- /dev/null
+++ b/apps/web/src/pages/api/query/transaction/index.ts
@@ -0,0 +1,63 @@
+import { gql } from 'graphql-request'
+import { bitQueryServerClient } from 'utils/graphql'
+
+const cache = {}
+
+const CACHE_EXPIRATION_TIME = 15 * 60 * 1000
+
+const cleanUpCache = () => {
+ const now = Date.now()
+ for (const key in cache) {
+ if (cache[key].timestamp + CACHE_EXPIRATION_TIME < now) {
+ delete cache[key]
+ }
+ }
+}
+
+const GET_TRANSACTIONS = gql`
+ query GetTransactions($sender: String!, $to: String!) {
+ ethereum(network: bsc) {
+ transactions(txSender: { is: $sender }, txTo: { is: $to }) {
+ hash
+ }
+ }
+ }
+`
+
+export default async function handler(req, res) {
+ const { sender, to } = req.query
+
+ if (!sender || !to) {
+ return res.status(400).json({ error: 'Sender and To addresses are required.' })
+ }
+
+ // Clean up stale cache entries before processing the request
+ cleanUpCache()
+
+ // Create a unique cache key based on the query parameters
+ const cacheKey = `${sender}_${to}`
+
+ // Check if data is in the cache and if it's still valid
+ const cachedData = cache[cacheKey]
+ const isCacheValid = cachedData && Date.now() - cachedData.timestamp < CACHE_EXPIRATION_TIME
+
+ if (isCacheValid) {
+ res.setHeader('Cache-Control', 'public, max-age=900') // Cache for 15 minutes
+ return res.status(200).json(cachedData.response)
+ }
+
+ try {
+ // Execute the query
+ const data = await bitQueryServerClient.request(GET_TRANSACTIONS, { sender, to })
+ const hashes = data.ethereum.transactions.map((tx) => tx.hash)
+
+ const responseToCache = { hashes }
+ cache[cacheKey] = { response: responseToCache, timestamp: Date.now() }
+
+ res.setHeader('Cache-Control', 'public, max-age=900') // Cache for 15 minutes
+ return res.status(200).json(responseToCache)
+ } catch (error) {
+ console.error(error)
+ return res.status(500).json({ error: 'Failed to fetch transaction data.' })
+ }
+}
diff --git a/apps/web/src/views/LimitOrders/components/LimitOrderTable/ExistingLimitOrderTable.tsx b/apps/web/src/views/LimitOrders/components/LimitOrderTable/ExistingLimitOrderTable.tsx
new file mode 100644
index 0000000000000..80ed0ce1ce0c2
--- /dev/null
+++ b/apps/web/src/views/LimitOrders/components/LimitOrderTable/ExistingLimitOrderTable.tsx
@@ -0,0 +1,135 @@
+import { useCallback } from 'react'
+import {
+ Table,
+ Th,
+ Text,
+ Button,
+ BscScanIcon,
+ Link,
+ Flex,
+ Box,
+ Td,
+ useToast,
+ useMatchBreakpoints,
+} from '@pancakeswap/uikit'
+import { useTranslation } from '@pancakeswap/localization'
+import { getBlockExploreLink } from 'utils'
+import { ChainId } from '@pancakeswap/chains'
+import { styled } from 'styled-components'
+import useGelatoLimitOrdersLib from 'hooks/limitOrders/useGelatoLimitOrdersLib'
+import { useAccount, usePublicClient, useWalletClient } from 'wagmi'
+import { useActiveChainId } from 'hooks/useActiveChainId'
+import { gelatoLimitABI } from 'config/abi/gelatoLimit'
+import { ToastDescriptionWithTx } from 'components/Toast'
+import useCatchTxError from 'hooks/useCatchTxError'
+import truncateHash from '@pancakeswap/utils/truncateHash'
+import { ExistingOrder } from 'views/LimitOrders/types'
+import { useQueryClient } from '@tanstack/react-query'
+import { EXISTING_ORDERS_QUERY_KEY } from 'views/LimitOrders/hooks/useGelatoLimitOrdersHistory'
+
+const RowStyle = styled.tr`
+ cursor: pointer;
+
+ &:hover {
+ background: ${({ theme }) => theme.colors.backgroundDisabled};
+ }
+`
+
+const ExistingLimitOrderTable = ({ orders }: { orders: ExistingOrder[] }) => {
+ const { t } = useTranslation()
+ const { isMobile } = useMatchBreakpoints()
+ const { address } = useAccount()
+ const { chainId } = useActiveChainId()
+ const publicClient = usePublicClient({ chainId })
+ const { data: walletClient } = useWalletClient()
+ const gelatoLimitOrders = useGelatoLimitOrdersLib()
+ const { toastSuccess } = useToast()
+ const { fetchWithCatchTxError } = useCatchTxError()
+ const queryClient = useQueryClient()
+
+ const handleCancelOrder = useCallback(
+ async (order: ExistingOrder) => {
+ if (publicClient && gelatoLimitOrders?.contract.address && walletClient) {
+ const { request } = await publicClient.simulateContract({
+ address: gelatoLimitOrders?.contract.address as `0x${string}`,
+ abi: gelatoLimitABI,
+ functionName: 'cancelOrder',
+ account: address,
+ args: [order.module, order.inputToken, order.owner, order.witness, order.data],
+ })
+
+ const receipt = await fetchWithCatchTxError(() => {
+ return walletClient.writeContract({
+ ...request,
+ gas: 5000000n,
+ })
+ })
+
+ if (receipt?.status) {
+ toastSuccess(t('Transaction receipt'),
+ |
+
+ |
+
+ |
+ + + | +
---|