From 6317da75d9b2775df2968664797846a3d10c09ce Mon Sep 17 00:00:00 2001 From: Luc Date: Wed, 22 Nov 2023 03:09:57 +0000 Subject: [PATCH] Introduce Deployed Resolvers --- .../organisms/deploy/DeployResolver.tsx | 29 ++- .../deployed_resolvers/DeployedResolvers.tsx | 116 +++++++++++ web/package.json | 1 + web/pages/app.tsx | 2 + web/pnpm-lock.yaml | 11 ++ web/stores/deployed_resolvers.tsx | 36 ++++ web/tailwind.config.js | 185 ++++++++++++++++++ 7 files changed, 378 insertions(+), 2 deletions(-) create mode 100644 web/components/organisms/deployed_resolvers/DeployedResolvers.tsx create mode 100644 web/stores/deployed_resolvers.tsx diff --git a/web/components/organisms/deploy/DeployResolver.tsx b/web/components/organisms/deploy/DeployResolver.tsx index 663131e..9b24db7 100644 --- a/web/components/organisms/deploy/DeployResolver.tsx +++ b/web/components/organisms/deploy/DeployResolver.tsx @@ -1,12 +1,14 @@ import { Button, Card, FlameSVG, GasPumpSVG, Input, OutlinkSVG, WalletSVG } from "@ensdomains/thorin"; import { useChains, useModal } from "connectkit"; import { FactoryABI } from "../../../pages/abi/factory_abi"; -import { FC, useMemo, useState } from "react"; +import { FC, useEffect, useMemo, useState } from "react"; import { Address, useAccount, useChainId, useContractWrite, useFeeData, usePrepareContractWrite, useWaitForTransaction } from "wagmi"; import { formatEther } from "viem"; +import { useDeployedResolvers } from "../../../stores/deployed_resolvers"; // https url that must include '{sender}' -const gatewayRegex = new RegExp("^https://.*{sender}.*$"); +// const gatewayRegex = new RegExp("^https://.*{sender}.*$"); +const gatewayRegex = new RegExp("^https://.*$"); // address[] that must include 0x and are seperated by , const signersRegex = new RegExp("^\\[0x[0-9a-fA-F]{40}(,0x[0-9a-fA-F]{40})*\\]$"); @@ -45,6 +47,8 @@ export const DeployResolverCard: FC = () => { const { data: FeeData } = useFeeData({ chainId, formatUnits: chainId == 5 ? 'kwei' : 'gwei' }); + const { transactions, logTransaction, logTransactionSuccess } = useDeployedResolvers(); + const { config, data: EstimateData, error, isSuccess, isLoading } = usePrepareContractWrite({ address: factoryAddress, chainId, @@ -70,6 +74,27 @@ export const DeployResolverCard: FC = () => { } }, [FeeData, EstimateData]); + console.log({ receipt: receipt?.data }); + + useEffect(() => { + if (!data) return; + + logTransaction(data.hash, chainId.toString()); + }, [data]); + + useEffect(() => { + if (!receipt?.data) return; + + const x = receipt.data; + + const first = x.logs[0]; + const address = first.address; + + console.log('Contracted Deployed at: ' + address); + + logTransactionSuccess(receipt.data.transactionHash, chainId.toString(), address); + }, [receipt?.data]); + return (
diff --git a/web/components/organisms/deployed_resolvers/DeployedResolvers.tsx b/web/components/organisms/deployed_resolvers/DeployedResolvers.tsx new file mode 100644 index 0000000..fdae91d --- /dev/null +++ b/web/components/organisms/deployed_resolvers/DeployedResolvers.tsx @@ -0,0 +1,116 @@ +import { FC } from "react"; +import { TransactionState, TransactionStateDeployed, TransactionStatePending, useDeployedResolvers } from "../../../stores/deployed_resolvers"; +import { useChainId, useContractRead, useTransaction } from "wagmi"; +import { Card, Input } from "@ensdomains/thorin"; +import { formatEther } from "viem"; +import { FiExternalLink, FiFile } from 'react-icons/fi'; + +export const DeployedResolvers = () => { + const transactions = useDeployedResolvers(e => e.transactions); + const chain = useChainId(); + + const transactionForChain = transactions.filter(transaction => transaction.chain == chain.toString()); + + return ( +
+ +

Deployed Resolvers

+ These are the resolvers you have deployed +
+
+ { + transactionForChain.map((transaction) => transaction.status == "deployed" ? + : ).reverse() + } +
+
+ ) +}; + +export const PendingTransaction: FC<{ transaction: TransactionState }> = ({ transaction: { hash, chain } }) => { + + return ( +
+
Pending
+
{hash}
+
{chain}
+
+ ); +}; + +const explorer_urls: Record = { + 1: { + transaction: 'https://etherscan.io/tx/:hash', + address: 'https://etherscan.io/address/:address' + }, + 5: { + transaction: 'https://goerli.etherscan.io/tx/:hash', + address: 'https://goerli.etherscan.io/address/:address' + }, +}; + +export const DeployedResolver: FC<{ transaction: TransactionStateDeployed }> = ({ transaction }) => { + const { data: gateway_data } = useContractRead({ + address: transaction.contract_address as any, + abi: [{ name: 'url', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ name: 'url', type: 'string' }] }], + functionName: 'url', + enabled: true, + }); + const { data: transactionData } = useTransaction({ + hash: transaction.hash as `0x${string}`, + chainId: Number.parseInt(transaction.chain), + }); + + const explorer_url = explorer_urls[Number.parseInt(transaction.chain)]; + const gateway_url = gateway_data as string; + + return ( + + +
+
+ Deployed at +
+
+ {transaction.hash} +
+ + TxHsh + +
+
+
+
+ Total Gas Fees +
+
+ + 🔥 + + + { + formatEther( + transactionData?.gasPrice?.mul(transactionData?.gasLimit).toBigInt() ?? BigInt(0)) + } + +
+
+
+ +
+
+
+ + ) +}; \ No newline at end of file diff --git a/web/package.json b/web/package.json index c469ede..78e0859 100644 --- a/web/package.json +++ b/web/package.json @@ -27,6 +27,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.43.9", + "react-icons": "^4.12.0", "styled-components": "^5.3.9", "tailwindcss": "^3.3.1", "viem": "^0.2.5", diff --git a/web/pages/app.tsx b/web/pages/app.tsx index 9ec1dc4..f1026f6 100644 --- a/web/pages/app.tsx +++ b/web/pages/app.tsx @@ -5,6 +5,7 @@ import { Configuration } from '../components/organisms/Configuration'; import { Thing } from './thing'; import { BannerCard } from '../components/organisms/BannerCard'; import { DeployResolverCard } from '../components/organisms/deploy/DeployResolver'; +import { DeployedResolvers } from '../components/organisms/deployed_resolvers/DeployedResolvers'; export const App = () => { return ( @@ -24,6 +25,7 @@ export const App = () => { {/* */} {/* */} +
diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index e9a76ae..61dfd39 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -43,6 +43,9 @@ dependencies: react-hook-form: specifier: ^7.43.9 version: 7.43.9(react@18.2.0) + react-icons: + specifier: ^4.12.0 + version: 4.12.0(react@18.2.0) styled-components: specifier: ^5.3.9 version: 5.3.9(react-dom@18.2.0)(react-is@16.13.1)(react@18.2.0) @@ -4957,6 +4960,14 @@ packages: react: 18.2.0 dev: false + /react-icons@4.12.0(react@18.2.0): + resolution: {integrity: sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: false + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} diff --git a/web/stores/deployed_resolvers.tsx b/web/stores/deployed_resolvers.tsx new file mode 100644 index 0000000..f39f6ad --- /dev/null +++ b/web/stores/deployed_resolvers.tsx @@ -0,0 +1,36 @@ +import { type } from 'os'; +import { create } from 'zustand'; +import { createJSONStorage, persist } from 'zustand/middleware'; + +export type TransactionStatePending = { status: 'pending', hash: string, chain: string }; +export type TransactionStateDeployed = { status: 'deployed', hash: string, chain: string, contract_address: string }; + +export type TransactionState = TransactionStatePending | TransactionStateDeployed; + +interface DeployedResolverState { + transactions: TransactionState[]; + logTransaction: (transaction_hash: string, chain_id: string) => void; + logTransactionSuccess: (transaction_hash: string, chain_id: string, contract_address: string) => void; +} + +export const useDeployedResolvers = create( + persist( + (set) => ({ + transactions: [], + logTransaction(transaction_hash, chain_id) { + set((state) => ({ transactions: [...state.transactions, { status: 'pending', hash: transaction_hash, chain: chain_id }] })) + }, + logTransactionSuccess(transaction_hash, chain_id, contract_address) { + set((state): Partial => { + const transactions = state.transactions.map((transaction) => { + if (transaction.hash === transaction_hash) { + return { ...transaction, status: 'deployed', contract_address } as TransactionStateDeployed; + } else { + return transaction; + } + }); + + return { transactions }; + }) + }, + }), { name: '@ccip-tools/resolvers', storage: createJSONStorage(() => localStorage) })); diff --git a/web/tailwind.config.js b/web/tailwind.config.js index c6b0d66..35e8521 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -33,6 +33,191 @@ module.exports = { greenlight: '#E7F4EF', yellowlight: '#FFF5CD', lgradient: '', + light: { + blue: { + DEFAULT: '#5298FF', + 50: '#FFFFFF', + 100: '#F5F9FF', + 200: '#CCE1FF', + 300: '#A4C9FF', + 400: '#7BB0FF', + 500: '#5298FF', + 600: '#1A77FF', + 700: '#005BE1', + 800: '#0044A9', + 900: '#002E71', + active: '#003685', + dim: '#056AFF', + primary: '#3889FF', + bright: '#569AFF', + light: '#D1E4FF', + surface: '#EEF5FF', + }, + indigo: { + active: '#19175F', + dim: '#342FC5', + primary: '#5854D6', + bright: '#7E7BDF', + light: '#C7C5F1', + surface: '#E3E2F8', + }, + purple: { + active: '#3D1353', + dim: '#8A2BBA', + primary: '#A343D3', + bright: '#B86EDD', + light: '#E3C6F1', + surface: '#EBD6F5', + }, + pink: { + active: '#440E28', + dim: '#AE2366', + primary: '#D52E7E', + bright: '#DE5999', + light: '#F4CDE0', + surface: '#EBD6F5', + }, + red: { + active: '#280A06', + dim: '#992515', + primary: '#C6301B', + bright: '#E34631', + light: '#F0C2C2', + surface: '#F9E7E7', + }, + orange: { + active: '#492C03', + dim: '#C37609', + primary: '#F3930B', + bright: '#F6A93C', + light: '#FBE1BC', + surface: '#FDF0DD', + }, + yellow: { + active: '#423505', + dim: '#B9930E', + primary: '#E9B911', + bright: '#F0C93C', + light: '#FFEFAD', + surface: '#FFF5CD', + }, + green: { + active: '#072C21', + dim: '#158463', + primary: '#199C75', + bright: '#1EB789', + green: '#CBE7DC', + surface: '#E7F4EF', + }, + grey: { + active: '#1E2122', + dim: '#595959', + primary: '#9B9BA7', + bright: '#B6B6BF', + light: '#E8E8E8', + surface: '#F6F6F6', + }, + text: { + primary: '#1E2122', + secondary: '#9B9BA7', + accent: '#FFFFFF', + disabled: '#B6B6BF', + }, + background: { + primary: '#FFFFFF', + secondary: '#F6F6F6', + disabled: '#E8E8E8', + }, + // Additional + border: '#E8E8E8', + }, + dark: { + blue: { + active: '#EEF5FF', + dim: '#D1E4FF', + primary: '#3889FF', + bright: '#056AFF', + light: '#0C4597', + surface: '#20395F', + }, + indigo: { + active: '#E3E2F8', + dim: '#C7C5F1', + primary: '#6B67E9', + bright: '#342FC5', + light: '#221E90', + surface: '#23216D', + }, + purple: { + active: '#EBD6F5', + dim: '#E3C6F1', + primary: '#A343D3', + bright: '#8A2BBA', + light: '#5E1683', + surface: '#42145A', + }, + pink: { + active: '#FAE8F1', + dim: '#F4CDE0', + primary: '#D52E7E', + bright: '#AE2366', + light: '#761544', + surface: '#5B1135', + }, + red: { + active: '#F9E7E7', + dim: '#F0C2C2', + primary: '#C6301B', + bright: '#A72614', + light: '#7F1313', + surface: '#3F2424', + }, + orange: { + active: '#FDF0DD', + dim: '#FBE1BC', + primary: '#F3930B', + bright: '#C37609', + light: '#6D4308', + surface: '#583503', + }, + yellow: { + active: '#FFF5CD', + dim: '#FFEFAD', + primary: '#E9B911', + bright: '#B9930E', + light: '#5C4B0C', + surface: '#373222', + }, + green: { + active: '#E7F4EF', + dim: '#CBE7DC', + primary: '#199C75', + bright: '#158463', + green: '#104A38', + surface: '#153C31', + }, + grey: { + active: '#F6F6F6', + dim: '#E8E8E8', + primary: '#9B9BA7', + bright: '#5D5C62', + light: '#424347', + surface: '#141416', + }, + text: { + primary: '#FFFFFF', + secondary: '#9B9BA7', + accent: '##FFFFFF', + disabled: '#5D5C62', + }, + background: { + primary: '#1E2122', + secondary: '#141416', + disabled: '##424347', + }, + // Additional + border: '#42464E', + }, }, // brand