From cbdfc5f44efbcaa0b77081d48031d40c395f5d1d Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:39:42 +0200 Subject: [PATCH 01/85] dark theme modified and added ui libraries --- packages/nextjs/package.json | 2 ++ packages/nextjs/tailwind.config.js | 16 +++++----- yarn.lock | 48 ++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 4dca602..06bd05b 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -23,6 +23,7 @@ "alchemy-sdk": "^2.9.2", "daisyui": "^2.31.0", "ethers": "^5.0.0", + "framer-motion": "^10.16.0", "next": "^13.1.6", "nextjs-progressbar": "^0.0.16", "react": "^18.2.0", @@ -43,6 +44,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.1.1", "@types/node": "^17.0.35", "@types/react": "^18.0.9", + "@types/react-dom": "^18.2.7", "@types/react-blockies": "^1.4.1", "@types/react-copy-to-clipboard": "^5.0.4", "@types/react-modal": "^3", diff --git a/packages/nextjs/tailwind.config.js b/packages/nextjs/tailwind.config.js index 925c88f..d77e132 100644 --- a/packages/nextjs/tailwind.config.js +++ b/packages/nextjs/tailwind.config.js @@ -34,17 +34,17 @@ module.exports = { }, { scaffoldEthDark: { - primary: "#212638", - "primary-content": "#F9FBFF", - secondary: "#323f61", - "secondary-content": "#F9FBFF", - accent: "#4969A6", - "accent-content": "#F9FBFF", + primary: "#17A9E8", + "primary-content": "#293853", + secondary: "#243148", + "secondary-content": "#9FAFCC", + accent: "#243148", + "accent-content": "#17A9E8", neutral: "#F9FBFF", "neutral-content": "#385183", "base-100": "#385183", - "base-200": "#2A3655", - "base-300": "#212638", + "base-200": "#243148", + "base-300": "#293853", "base-content": "#F9FBFF", info: "#385183", success: "#34EEB6", diff --git a/yarn.lock b/yarn.lock index 3b95ce4..56c0670 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1582,6 +1582,22 @@ __metadata: languageName: node linkType: hard +"@emotion/is-prop-valid@npm:^0.8.2": + version: 0.8.8 + resolution: "@emotion/is-prop-valid@npm:0.8.8" + dependencies: + "@emotion/memoize": 0.7.4 + checksum: bb7ec6d48c572c540e24e47cc94fc2f8dec2d6a342ae97bc9c8b6388d9b8d283862672172a1bb62d335c02662afe6291e10c71e9b8642664a8b43416cdceffac + languageName: node + linkType: hard + +"@emotion/memoize@npm:0.7.4": + version: 0.7.4 + resolution: "@emotion/memoize@npm:0.7.4" + checksum: 4e3920d4ec95995657a37beb43d3f4b7d89fed6caa2b173a4c04d10482d089d5c3ea50bbc96618d918b020f26ed6e9c4026bbd45433566576c1f7b056c3271dc + languageName: node + linkType: hard + "@esbuild-plugins/node-modules-polyfill@npm:^0.1.4": version: 0.1.4 resolution: "@esbuild-plugins/node-modules-polyfill@npm:0.1.4" @@ -3665,6 +3681,7 @@ __metadata: "@types/react": ^18.0.9 "@types/react-blockies": ^1.4.1 "@types/react-copy-to-clipboard": ^5.0.4 + "@types/react-dom": ^18.2.7 "@types/react-modal": ^3 "@typescript-eslint/eslint-plugin": ^5.39.0 "@uniswap/sdk-core": ^4.0.1 @@ -3677,6 +3694,7 @@ __metadata: eslint-config-prettier: ^8.5.0 eslint-plugin-prettier: ^4.2.1 ethers: ^5.0.0 + framer-motion: ^10.16.0 next: ^13.1.6 nextjs-progressbar: ^0.0.16 postcss: ^8.4.16 @@ -4527,6 +4545,15 @@ __metadata: languageName: node linkType: hard +"@types/react-dom@npm:^18.2.7": + version: 18.2.7 + resolution: "@types/react-dom@npm:18.2.7" + dependencies: + "@types/react": "*" + checksum: e02ea908289a7ad26053308248d2b87f6aeafd73d0e2de2a3d435947bcea0422599016ffd1c3e38ff36c42f5e1c87c7417f05b0a157e48649e4a02f21727d54f + languageName: node + linkType: hard + "@types/react-modal@npm:^3": version: 3.16.0 resolution: "@types/react-modal@npm:3.16.0" @@ -10272,6 +10299,27 @@ __metadata: languageName: node linkType: hard +"framer-motion@npm:^10.16.0": + version: 10.16.0 + resolution: "framer-motion@npm:10.16.0" + dependencies: + "@emotion/is-prop-valid": ^0.8.2 + tslib: ^2.4.0 + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependenciesMeta: + "@emotion/is-prop-valid": + optional: true + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + checksum: 155fd0fc81b45d91583625aaa3b970785bd7e2c552d1f5b9afd5caafa7c3f2b545200aefdb98f3082f50f7472eb49630f8890f5a772cd2f90b87a1c935b21332 + languageName: node + linkType: hard + "fresh@npm:0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" From ca12c06145a849972223b11369b475cbe74c09ce Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:40:14 +0200 Subject: [PATCH 02/85] header --- .../CustomHeader/CustomHeader.tsx | 15 +++++++++++ .../CustomHeader/customheader.module.css | 26 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 packages/nextjs/components/flashbotRecovery/CustomHeader/CustomHeader.tsx create mode 100644 packages/nextjs/components/flashbotRecovery/CustomHeader/customheader.module.css diff --git a/packages/nextjs/components/flashbotRecovery/CustomHeader/CustomHeader.tsx b/packages/nextjs/components/flashbotRecovery/CustomHeader/CustomHeader.tsx new file mode 100644 index 0000000..cf41b8b --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/CustomHeader/CustomHeader.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import styles from "./customheader.module.css" +import Image from 'next/image' +import LogoSvg from "../../../public/assets/flashbotRecovery/logo.svg" + +export const CustomHeader = () => { + return ( +
+
+ + Recovery Flashbot +
+
+ ) +} diff --git a/packages/nextjs/components/flashbotRecovery/CustomHeader/customheader.module.css b/packages/nextjs/components/flashbotRecovery/CustomHeader/customheader.module.css new file mode 100644 index 0000000..0aeb387 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/CustomHeader/customheader.module.css @@ -0,0 +1,26 @@ +.header{ + width: 100%; +} + +.logoContainer{ + display: flex; + align-items: center; + margin-top: 20px; + margin-left: 10px; + font-size: 23px; +font-style: normal; +font-weight: 400; +} + +.logo{ + width: 60px; + height: 60px; + margin-right: 16px; +} + +@media (min-width: 768px) { + .logoContainer{ + margin-top: 56px; + margin-left: 96px; + } +} \ No newline at end of file From aef39afc215e64d2bbe191e2af665d78ee33539f Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:40:32 +0200 Subject: [PATCH 03/85] connect step --- packages/nextjs/components/Footer.tsx | 2 +- .../ConnectStep/ConnectStep.tsx | 32 ++++++++++++++++ .../ConnectStep/connectStep.module.css | 38 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 packages/nextjs/components/flashbotRecovery/ConnectStep/ConnectStep.tsx create mode 100644 packages/nextjs/components/flashbotRecovery/ConnectStep/connectStep.module.css diff --git a/packages/nextjs/components/Footer.tsx b/packages/nextjs/components/Footer.tsx index 444100b..15a4577 100644 --- a/packages/nextjs/components/Footer.tsx +++ b/packages/nextjs/components/Footer.tsx @@ -11,7 +11,7 @@ import { getTargetNetwork } from "~~/utils/scaffold-eth"; */ export const Footer = () => { return ( -
+
diff --git a/packages/nextjs/components/flashbotRecovery/ConnectStep/ConnectStep.tsx b/packages/nextjs/components/flashbotRecovery/ConnectStep/ConnectStep.tsx new file mode 100644 index 0000000..5e579f1 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/ConnectStep/ConnectStep.tsx @@ -0,0 +1,32 @@ +import React from "react"; +import Image from "next/image"; +import IllustrationSvg from "../../../public/assets/flashbotRecovery/logo.svg" +import styles from "./connectStep.module.css" +import { RainbowKitCustomConnectButton } from "~~/components/scaffold-eth"; +import { AnimatePresence, motion } from "framer-motion"; +interface IProps{ + isVisible:boolean +} +export const ConnectStep = ({isVisible}:IProps) => { + + return + {isVisible && ( + +

Welcome to Flashbot Recovery

+ +

+ Lorem ipsum dolor sit amet, consectetur dipiscing elit. Nunc vulputate libero et velit interdum, ac aliquet + odio mattis. +

+
+ +
+
+ )} +
+}; \ No newline at end of file diff --git a/packages/nextjs/components/flashbotRecovery/ConnectStep/connectStep.module.css b/packages/nextjs/components/flashbotRecovery/ConnectStep/connectStep.module.css new file mode 100644 index 0000000..61b0125 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/ConnectStep/connectStep.module.css @@ -0,0 +1,38 @@ +.container{ + max-width: 580px; + margin: 20px; + margin-bottom: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.title{ + text-align: center; + font-size: 24px; + font-style: normal; + font-weight: 700; + line-height: 32px; +} +.illustration{ + width: 250px; + height: 250px; + margin: 40px 0; +} +.text{ + font-size: 18px; + font-style: normal; + font-weight: 400; + font-size: 18px; + line-height: 32px; + text-align: center; +} +.buttonContainer button{ + display: flex; + +height: 40px; +padding: 0px 48px; +} +.buttonContainer > div > div >div{ +display: none; +} \ No newline at end of file From cd63a493df252d7fbc0f5d99c16ff49c46c38601 Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:40:44 +0200 Subject: [PATCH 04/85] asset selection --- .../AssetSelectionStep/AssetSelectionStep.tsx | 68 +++++++++++++++++++ .../assetSelectionStep.module.css | 61 +++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx create mode 100644 packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css diff --git a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx new file mode 100644 index 0000000..22e98c2 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx @@ -0,0 +1,68 @@ +import React, { useState } from "react"; +import styles from "./assetSelectionStep.module.css"; +import { AnimatePresence, motion } from "framer-motion"; +import LogoSvg from "../../../public/assets/flashbotRecovery/logo.svg"; + +import Image from "next/image"; + +interface IProps { + isVisible: boolean; +} +export const AssetSelectionStep = ({ isVisible }: IProps) => { + const [selectedAssets, setSelectedAssets] = useState([]) + const list = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]; + + + const onAssetSelected = (i:number) => { + const currentIndex = selectedAssets.indexOf(i); + let newAssets:number[] = []; + if(currentIndex === -1){ + newAssets.push(i) + newAssets.push(...selectedAssets) + }else{ + newAssets = selectedAssets.filter(item => item !== i) + } + setSelectedAssets(newAssets); + } + return ( + + {isVisible && ( + +

Your assets

+
+ {list.map((item, i) => onAssetSelected(i)}/>)} +
+ +
+ )} +
+ ); +}; + +interface IAssetProps{ + onClick:() => void; + isSelected:boolean +} + + +const AssetItem = ({onClick, isSelected}:IAssetProps) => { + return onClick()} + className={`${isSelected ? "bg-base-200" : ""} ${styles.assetItem}`} +> +
+ +
+
+

Name

+ ID +
+
+} diff --git a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css new file mode 100644 index 0000000..ebadd77 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css @@ -0,0 +1,61 @@ +.container{ + width: 100%; + + margin-bottom: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.title{ + font-size: 23px; + font-style: normal; + font-weight: 600; + line-height: 100%; + margin: 0; +} +.assetItem{ + display: flex; + height: 92px; + max-width: 458px; + margin: 0 auto; + border-radius: 12px; + cursor: pointer; + margin-bottom: 12px; +} +.data{ + display: flex; + flex-direction: column; + justify-content: center; +} +.assetList{ + width: 100%; + max-height: calc(100vh - 400px); + overflow: auto; + margin: 36px 0; +} + +.button{ + width: 200px; + margin: 0 auto; + padding: 0px 48px; + height: 40px; + font-size: 16px; +font-style: normal; +font-weight: 700; +line-height: normal; +} + +.logo{ + width: 60px; + height: 60px; + margin-right: 16px; +} + +.logoContainer{ + display: flex; + flex-direction: column; + justify-content: center; + margin-left:16px; +} \ No newline at end of file From be158b9ef5a7db159aa374c2819d3570a16d2fb4 Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:40:57 +0200 Subject: [PATCH 05/85] hacked address --- .../HackedAddressStep/HackedAddressStep.tsx | 38 +++++++++++++++++++ .../hackedAddressStep.module.css | 30 +++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx create mode 100644 packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css diff --git a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx new file mode 100644 index 0000000..b618596 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import Image from "next/image"; +import IllustrationSvg from "../../../public/assets/flashbotRecovery/logo.svg"; +import styles from "./hackedAddressStep.module.css"; +import { AnimatePresence, motion } from "framer-motion"; +import { useLocalStorage } from "usehooks-ts"; +import { AddressInput, RainbowKitCustomConnectButton } from "~~/components/scaffold-eth"; + +interface IProps { + isVisible: boolean; +} +export const HackedAddressStep = ({ isVisible }: IProps) => { + const [hackedAddress, setHackedAddress] = useLocalStorage("hackedAddress", ""); + + return ( + + {isVisible && ( + + + + + + )} + + ); +}; diff --git a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css new file mode 100644 index 0000000..3a85528 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css @@ -0,0 +1,30 @@ +.container{ + width: 90%; + margin-bottom: 0; + display: flex; + flex-direction: column; + justify-content: center; + max-width: 458px; +} + +.label{ + font-size: 16px; +font-style: normal; +font-weight: 600; +line-height: normal; +margin-bottom: 12px; +} +.container > div{ + border-radius: 4px; +} +.button{ + width: 200px; + margin: 0 auto; + margin-top: 40px; + padding: 0px 48px; + height: 40px; + font-size: 16px; +font-style: normal; +font-weight: 700; +line-height: normal; +} \ No newline at end of file From c2964a95481e0557cb108b0574e52083ddb98e95 Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:41:05 +0200 Subject: [PATCH 06/85] layout --- .../flashbotRecovery/Layout/Layout.tsx | 73 +++++++++++++ .../flashbotRecovery/Layout/layout.module.css | 100 ++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 packages/nextjs/components/flashbotRecovery/Layout/Layout.tsx create mode 100644 packages/nextjs/components/flashbotRecovery/Layout/layout.module.css diff --git a/packages/nextjs/components/flashbotRecovery/Layout/Layout.tsx b/packages/nextjs/components/flashbotRecovery/Layout/Layout.tsx new file mode 100644 index 0000000..3434278 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/Layout/Layout.tsx @@ -0,0 +1,73 @@ +import React from "react"; +import Image from "next/image"; +import LogoSvg from "../../../public/assets/flashbotRecovery/logo.svg"; +import styles from "./layout.module.css"; +import { motion } from "framer-motion"; + +interface IProps { + children: JSX.Element; + stepActive: number; +} +export const Layout = ({ children, stepActive }: IProps) => { + return ( + +
+
+
+ + Recovery Flashbot +
+
+ + + + + + +
+
+
+
{children}
+
+ ); +}; + +interface IStepProps { + isActive: boolean; + index: number; + title: string; + description: string; +} +const Step = ({ isActive, index, title, description }: IStepProps) => { + return ( +
+
+ {index} +
+
+

{title}

+

{description}

+
+
+ ); +}; diff --git a/packages/nextjs/components/flashbotRecovery/Layout/layout.module.css b/packages/nextjs/components/flashbotRecovery/Layout/layout.module.css new file mode 100644 index 0000000..3398013 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/Layout/layout.module.css @@ -0,0 +1,100 @@ +.layout { + display: flex; + justify-content: flex-start; + align-items: flex-start; + width: 100%; + height: 100vh; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; +} +.sidebar { + max-width: 530px; + display: flex; + width: auto; + + background-color: #243148; + height: 100%; +} + +.sidebarContent { + margin-top: 56px; + margin-left: 10px; + +} +.content { + display: flex; + width: 100%; + height: 100%; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.logoContainer { + display: flex; + align-items: center; + font-size: 23px; + font-style: normal; + font-weight: 400; +} + +.logo { + width: 60px; + height: 60px; + margin-right: 16px; +} +.steps{ + margin-top: 68px; + margin-right: 63px; +} +.step { + display: flex; + margin-top: 30px; +} +.badge { + border-radius: 100px; + border: 2px solid; + display: flex; + width: 40px; + font-size: 24px; +font-style: normal; +font-weight: 600; + height: 40px; + flex-direction: column; + justify-content: center; + align-items: center; +} +.stepContainer { + margin-left: 16px; +} +.stepTitle { + font-size: 20px; +font-style: normal; +font-weight: 600; +margin: 0; + display: flex; + height: 40px; + align-items: center; + +} +.stepDescription { + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 26px; + margin: 0; +} + + + + + + + @media (min-width: 768px) { + .sidebarContent { + margin-left: 96px; + } +} \ No newline at end of file From 3b8b28ed72eeb110ead708dc4007f0802c13f013 Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:41:17 +0200 Subject: [PATCH 07/85] transaction bundle step --- .../transactionBundleStep.module.css | 82 +++++++++++++++++++ .../transactionBundleStep.tsx | 77 +++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css create mode 100644 packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx diff --git a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css new file mode 100644 index 0000000..508e40a --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css @@ -0,0 +1,82 @@ +.container{ + width: 100%; + + margin-bottom: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.title{ + font-size: 23px; + font-style: normal; + font-weight: 600; + line-height: 100%; + margin: 0; +} +.assetItem{ + display: flex; + height: 42px; + max-width: 600px; + margin: 0 auto; + cursor: pointer; + border-radius: 4px; + margin-bottom: 12px; +} +.data{ + display: flex; + flex-direction: column; + justify-content: center; + flex-grow: 1; + margin-left: 16px; +} +.data h3{ + margin: 0; + font-size: 18px; +font-style: normal; +font-weight: 500; +} +.assetList{ + width: 100%; + max-height: calc(100vh - 400px); + overflow: auto; + margin: 36px 0; + margin-bottom: 0; +} + +.button{ + width: 230px; + margin: 0 auto; + padding: 0px 48px; + height: 40px; + font-size: 16px; + font-style: normal; + font-weight: 700; + line-height: normal; + border: 1px solid; +} +.clear{ + text-decoration: underline; + width: 230px; + margin-bottom: 42px; + margin-top: 16px; + text-align: center; + cursor: pointer; +} +.clear:hover{ + color:#17A9E8 +} +.logo{ + width: 60px; + height: 60px; + margin-right: 16px; +} + +.logoContainer{ + display: flex; + flex-direction: column; + justify-content: center; + margin-left:16px; + margin-right: 16px; +} \ No newline at end of file diff --git a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx new file mode 100644 index 0000000..52d0a8c --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx @@ -0,0 +1,77 @@ +import React, { useState } from "react"; +import Image from "next/image"; +import LogoSvg from "../../../public/assets/flashbotRecovery/logo.svg"; +import styles from "./transactionBundleStep.module.css"; +import { AnimatePresence, motion } from "framer-motion"; + +interface IProps { + isVisible: boolean; +} +export const TransactionBundleStep = ({ isVisible }: IProps) => { + const [selectedAssets, setSelectedAssets] = useState([]); + const list = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; + + const onAssetSelected = (i: number) => { + const currentIndex = selectedAssets.indexOf(i); + let newAssets: number[] = []; + if (currentIndex === -1) { + newAssets.push(i); + newAssets.push(...selectedAssets); + } else { + newAssets = selectedAssets.filter(item => item !== i); + } + setSelectedAssets(newAssets); + }; + + return ( + + {isVisible && ( + +

Your transactions

+
+ {list.map((item, i) => ( + onAssetSelected(i)} + title={i%2 === 0 ? "Custom call (transfer) to 0x24923bah971904020q9q98198y83": "NFT recovery for tokenID 1"} + /> + ))} +
+ Clear all +
+ +
+ +
+ )} +
+ ); +}; + +interface ITransactionProps { + onDelete: () => void; + isSelected: boolean; + title: string; +} + +const TransactionItem = ({ onDelete, title }: ITransactionProps) => { + return ( + onDelete()} + className={`${styles.assetItem} bg-base-200 text-secondary-content`} + > +
+

{title}

+
+
X
+
+ ); +}; From 4674d71762cbb510e6d8209a4d42510071c88063 Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:41:36 +0200 Subject: [PATCH 08/85] custom portal --- .../CustomPortal/CustomPortal.tsx | 57 ++++++++++++++ .../CustomPortal/customPortal.module.css | 74 +++++++++++++++++++ packages/nextjs/pages/_document.tsx | 16 ++++ 3 files changed, 147 insertions(+) create mode 100644 packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx create mode 100644 packages/nextjs/components/flashbotRecovery/CustomPortal/customPortal.module.css create mode 100644 packages/nextjs/pages/_document.tsx diff --git a/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx b/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx new file mode 100644 index 0000000..f90fd55 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx @@ -0,0 +1,57 @@ +import { useEffect, useState } from "react"; +import Image from "next/image"; +import styles from "./customPortal.module.css"; +import { createPortal } from "react-dom"; +import CloseSvg from "../../../public/assets/flashbotRecovery/close.svg"; +import { motion } from "framer-motion"; + +interface IProps { + title: string; + image?: string; + video?: string; + description: string; + button?:{ + text:string, + action:() => void + } +} +export const CustomPortal = ({ title, image, video, description, button}: IProps) => { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + + return () => setMounted(false); + }, []); + const portalSelector = document.querySelector("#myportal"); + if (!portalSelector) { + return <>; + } + + return mounted + ? createPortal( + +
+ setMounted(false)}> + {" "} + {""} + +
+ + +

{title}

+ {!!image ? {""} : <>} + {!!video ?
+
+
, + portalSelector, + ) + : null; +}; diff --git a/packages/nextjs/components/flashbotRecovery/CustomPortal/customPortal.module.css b/packages/nextjs/components/flashbotRecovery/CustomPortal/customPortal.module.css new file mode 100644 index 0000000..6f0ad77 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/CustomPortal/customPortal.module.css @@ -0,0 +1,74 @@ +.modalContainer { + position: absolute; + top: 0; + bottom: 0; + width: 100vw; + height: 100vh; + backdrop-filter: blur(5px); + display: flex; + justify-content: center; + align-items: center; + background: rgba(20, 28, 41, 0.40); +} + +.modal { + display: inline-flex; + width: 579px; + flex-direction: column; + align-items: center; + gap: 40px; + flex-shrink: 0; + border-radius: 12px; + box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.03); + +} + +.modalContent{ + display: inline-flex; + flex-direction: column; + align-items: center; + gap: 40px; + flex-shrink: 0; + margin-bottom: 56px; +} +.button{ + width: 230px; + margin: 0 auto; + font-size: 16px; + font-style: normal; + font-weight: 700; + line-height: normal; + border: 1px solid; +} + +.close{ + align-self: flex-end; + margin-top: 14px; + margin-right: 14px; + cursor: pointer; + padding: 10px; + padding-bottom: 4px; +} + +.title{ + font-size: 24px; +font-style: normal; +font-weight: 700; +line-height: 32px; +margin:0; +} + +.image{ + height: 250px; + width: 467px; +} + +.text{ + font-size: 18px; +font-style: normal; +font-weight: 400; +line-height: 32px; +width: 80%; +text-align: center; +margin: 0; +} \ No newline at end of file diff --git a/packages/nextjs/pages/_document.tsx b/packages/nextjs/pages/_document.tsx new file mode 100644 index 0000000..4013196 --- /dev/null +++ b/packages/nextjs/pages/_document.tsx @@ -0,0 +1,16 @@ +import Document, { Html, Head, Main, NextScript } from "next/document" + +export default class MyDocument extends Document { + render() { + return ( + + + +
+
+ + + + ) + } +} \ No newline at end of file From 82e1a3fac7725ca08c90f480c4f3fb11fb4ebb6c Mon Sep 17 00:00:00 2001 From: Fran Date: Sun, 20 Aug 2023 21:41:50 +0200 Subject: [PATCH 09/85] assets and globals --- .../public/assets/flashbotRecovery/close.svg | 11 +++++++++ .../assets/flashbotRecovery/illustration.svg | Bin 0 -> 3702 bytes .../public/assets/flashbotRecovery/logo.svg | 3 +++ .../public/assets/flashbotRecovery/video.svg | 4 ++++ packages/nextjs/styles/globals.css | 22 ++++++++++++++++++ 5 files changed, 40 insertions(+) create mode 100644 packages/nextjs/public/assets/flashbotRecovery/close.svg create mode 100644 packages/nextjs/public/assets/flashbotRecovery/illustration.svg create mode 100644 packages/nextjs/public/assets/flashbotRecovery/logo.svg create mode 100644 packages/nextjs/public/assets/flashbotRecovery/video.svg diff --git a/packages/nextjs/public/assets/flashbotRecovery/close.svg b/packages/nextjs/public/assets/flashbotRecovery/close.svg new file mode 100644 index 0000000..e2dfd89 --- /dev/null +++ b/packages/nextjs/public/assets/flashbotRecovery/close.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/packages/nextjs/public/assets/flashbotRecovery/illustration.svg b/packages/nextjs/public/assets/flashbotRecovery/illustration.svg new file mode 100644 index 0000000000000000000000000000000000000000..77c57fbf5379221bbf8dacc967218221e433c645 GIT binary patch literal 3702 zcmeH~`#%$k8^`C=;gs7!os{TulsXn7G;^t><+z?h&2pJyIT3TromtdL6pES%J8~;! zZZWrQR6_j@xd6Zq9$eUNc7~jH zI}ZTV=cvlBe-8j?s5)Of?;WqS%v?a}aP>QdkX+4Oht{?Gz6%O6L7gqqC{_CPgxm4{ za<}2n)(H$Kdi2(Y%4`gHWcCVt4FMi0D8H3!weWPf$NA2^vp;rbDD7w#h68>3RGJYk zjLluOussugR`w}u+N16Uo2%v

a4!<_BhXDiq^2{qThwR`|@vAn!Ub?-l^~1GYX9 zeS9j+)M~s#5xeR-zUCU&RSHcZoQinM>QM)3#D2PaIwxkX$6$njrwdlNXFuR!E(@8RQI%g?GdaQZgX_hN zdGwMv^FxmiGft+yeY3iNhyIm2aaY#-96iu(u2(n0fN_njuu5*k7e3n$aQU5?iJXl3MpZ-J*hllT zsS8ecWK?E02A^Mp-TF(pGxsKJ>Y(5rq8_S(wV~wASOUBc$DZ4DL*?mz_*X3uJ0I)n zI47+RZ0;(0%ti)8xZm&UaJJYjUtHtjE;nt(QwdqrWq(JRB;q9A4}KN6v`8Y4{kh@i z=!11M-o42|^imKB@$rUuGQXy5@9oOE+-AUUKp*eO7q+>0-6qm%8E zTB$Gt-GkW!xUBJZ88#$DhLDP$jn%;}?&dkp{G1*ks3~ulBV(faZEp^Wd)pPZf1U)1 z?_;x9uxk~)Wj_ZEp<>)t#j@o^5@>o$f{7Zh9KEC!Qx9*U)AKv{$(v0Nd;gv5X1CLSq64Vy|hL=QIzGQ^-b=SA@emWb$@($poFi$PBp3um0{M~tE&|VtFm7z8KisbqE(sIy{kWMP=UFhao~=s zqoC*`wAREB!~%-OD-cE|F)D}U%f91(@+i7R~SO6!TQ?xvGLjye?F}D!kTq zA2CagLcvICk^PCXkB4V@tQ?FmJm^09V`8MBxkoke#?hbNNJZ~sUD zlm~3ux_6WfW%zKjE>C|fON1bPb02HC1Eg?_NUxDg1i{ab3-}Buv90@fK*N$j&fR$OYu?ykA=( zt_gE&Af4F*q_+pnys|h}=$d_TwmHkKc(b73)|8u=y_w2LLMJf8p!va;O)(mJoCoMs zpOWGid|+IhMC0sv%8~iyu9_Ah^QNT0baszurxAxN3=;uJS;p*aBiykDQVGkRQKF3;AZ@( zD2-l@`rKx}wUz`8?m{+e4$EM zBrr~2;;*iHRfU9@D0&t)n!UUHnh7xpg;GIFfnINy{I#Q`&Be_jKBb9k@)se($EyhY zb+vzrZ0IxZu{XT?S$6y20!P{ub6;i5!{B6vbU0bLhvex;8nf}d0{iJ1@kvJ=N1iOe z574Qpr9=Ekg(n0;Te+PaSc!?8>kgCNaW#7`AjJKX`WA@kGnWZ>ezz5Ep%N7pfwOv` zXJ-xZ@~<))cHliay=O0HCqGV8zbPk5jelYLYme&T zWh1x}TQ+lO6dZc9pva*eLS-F)S^u2pPd#{Gzn;f_Zj15cw`lR_oHY8rA3+{llq8&A zuGZq{o6Lqx=$>E>!c_IFkRn}fbeJOYk%Do*!sP`+i8r=~H9WL;mqa~Fd`||kN!qwn zDNE_{bMa``SzkY!v;;ZNL!AgoILvy-CYpdL7#cFg*-sQ?di)YjXT(b^Z$k0guCuC{ zZF^8O%{O!sMsf~Tt<=$Kb~Zk&2lO;QK{ScF>!2G>^DVKn933CAFk6D0DKw+mQ(oeU zwEH4YlFS_B9c$l__crlE-^=`LTi6x_r_Vg$<;15L%3nA-N|H<4C25*Re{4ZLFd2#K zFGaE&OxT}N$M_|$mAW!Txyc2HNVo}ENAki`r1EqnklsjZ&=Ut1TKsJ|;$5qlj;yeQ z8}w_eTUy^KF&oh}{8#;>EVrgZyx01Jp zvwQdE%&^0m;i*w@G?^JQQ!BC=_SW~)zXpy z^FRTTbQ{C(xHI()aiO;bnYUpWt`qO^zLehTXVNGzH!o-ujEPsQsn@X3_=MXNsuCyV z`$bYDDC)Uw;(QC6&arPxJZcS9Ue#fYCF&Y1-+R|%1J`c#vaeno-d1# z1t~C{e3U{KR(4eE&Aof$cA5YbW^S(i z&`omf^SNFS`0wJPMvDWQC(iTkX!mIRhkwC>fSGz_^*hI?VZCJmIY#chPVErs+q$?4 z)7tU)PtTR=3}JnlDZ(j6@l@PYg2m$L66GC%&JB+Uuq{`$&%Jg!)a}1MxR)3*>w%M3 zai*b;oENykx_u9~cXrPRzo3O(hw%NPFJBm$?|2plLAq~uV1HO>MMv}AuEyaSJ>hU2 zU!t%x2KV6?f}(Ic3tiLRxX6^$t{x)BP+(jXymU>}|HsjI9peUx0<;}=bR<6d!uUyy zN6NaaJ^PE@2rE!wOlHkD+P0qxdSKwA7QEZez(FQeL5^0C)(tes8<${b_^_qZ!V5{6 w_|E_zU0%x!HsgTK(zkdjqQC{Wu&7Xx4~MINEcy0kJ0=30o!l?tF9fFj50c_RUH||9 literal 0 HcmV?d00001 diff --git a/packages/nextjs/public/assets/flashbotRecovery/logo.svg b/packages/nextjs/public/assets/flashbotRecovery/logo.svg new file mode 100644 index 0000000..7125321 --- /dev/null +++ b/packages/nextjs/public/assets/flashbotRecovery/logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/nextjs/public/assets/flashbotRecovery/video.svg b/packages/nextjs/public/assets/flashbotRecovery/video.svg new file mode 100644 index 0000000..15c4a48 --- /dev/null +++ b/packages/nextjs/public/assets/flashbotRecovery/video.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/nextjs/styles/globals.css b/packages/nextjs/styles/globals.css index 8090d38..903bed2 100644 --- a/packages/nextjs/styles/globals.css +++ b/packages/nextjs/styles/globals.css @@ -1,7 +1,29 @@ @import "tailwindcss/base"; @import "tailwindcss/components"; @import "tailwindcss/utilities"; +@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&family=Ubuntu:wght@300;400;500;700&display=swap"); +* { + scrollbar-width: auto; + scrollbar-color: #1aa8e8 #253148; +} + +/* Chrome, Edge, and Safari */ +*::-webkit-scrollbar { + width: 12px; +} + +*::-webkit-scrollbar-track { + background: #253148; +} + +*::-webkit-scrollbar-thumb { + background-color: #1aa8e8; + border-radius: 10px; +} +body * { + font-family: "Inter", sans-serif; +} :root, [data-theme] { background: hsl(var(--b2)); From 43937d29bb4b7cc7ebfef7f10860905938795fb0 Mon Sep 17 00:00:00 2001 From: Fran Date: Mon, 21 Aug 2023 01:06:03 +0200 Subject: [PATCH 10/85] add functionality until autodetect transactions --- .../AssetSelectionStep/AssetSelectionStep.tsx | 177 +++++++--- .../assetSelectionStep.module.css | 42 ++- .../HackedAddressStep/HackedAddressStep.tsx | 65 ++-- .../hackedAddressStep.module.css | 1 + .../flashbotRecovery/Layout/Layout.tsx | 18 +- .../transactionBundleStep.module.css | 6 +- .../transactionBundleStep.tsx | 105 +++--- .../useAutodetectAssets.ts | 327 ++++++++++++++++++ 8 files changed, 596 insertions(+), 145 deletions(-) create mode 100644 packages/nextjs/hooks/flashbotRecoveryBundle/useAutodetectAssets.ts diff --git a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx index 22e98c2..355eb43 100644 --- a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx +++ b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx @@ -1,68 +1,139 @@ -import React, { useState } from "react"; -import styles from "./assetSelectionStep.module.css"; -import { AnimatePresence, motion } from "framer-motion"; -import LogoSvg from "../../../public/assets/flashbotRecovery/logo.svg"; - +import React, { useEffect, useState } from "react"; import Image from "next/image"; +import LogoSvg from "../../../public/assets/flashbotRecovery/logo.svg"; +import styles from "./assetSelectionStep.module.css"; +import { motion } from "framer-motion"; +import { useAutodetectAssets } from "~~/hooks/flashbotRecoveryBundle/useAutodetectAssets"; +import { RecoveryTx } from "~~/types/business"; interface IProps { isVisible: boolean; + hackedAddress: string; + safeAddress: string; + onSubmit: (txs: RecoveryTx[]) => void; } -export const AssetSelectionStep = ({ isVisible }: IProps) => { - const [selectedAssets, setSelectedAssets] = useState([]) - const list = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]; - +export const AssetSelectionStep = ({ isVisible, onSubmit, hackedAddress, safeAddress }: IProps) => { - const onAssetSelected = (i:number) => { - const currentIndex = selectedAssets.indexOf(i); - let newAssets:number[] = []; - if(currentIndex === -1){ - newAssets.push(i) - newAssets.push(...selectedAssets) - }else{ - newAssets = selectedAssets.filter(item => item !== i) + const { getAutodetectedAssets } = useAutodetectAssets(); + const [selectedAssets, setSelectedAssets] = useState([]); + const [accountAssets, setAccountAssets] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const onAssetSelected = (index: number) => { + const currentIndex = selectedAssets.indexOf(index); + let newAssets: number[] = []; + if (currentIndex === -1) { + newAssets.push(index); + newAssets.push(...selectedAssets); + } else { + newAssets = selectedAssets.filter(item => item !== index); } setSelectedAssets(newAssets); + }; + + useEffect(() => { + if (accountAssets.length > 0 || !isVisible) { + return; + } + init(); + }, [isVisible]); + + const init = async () => { + const result = await getAutodetectedAssets({ hackedAddress, safeAddress }); + if (!result) { + return; + } + setAccountAssets(result); + setIsLoading(false); + }; + + const onAddAssetsClick = () => { + const txsToAdd = accountAssets.filter((item, i) => selectedAssets.indexOf(i) != -1); + onSubmit(txsToAdd); + }; + if (!isVisible) { + return <>; } return ( - - {isVisible && ( - -

Your assets

-
- {list.map((item, i) => onAssetSelected(i)}/>)} -
- - - )} - + +

Your assets

+ +
+ {!!isLoading + ? [1, 2, 3].map((item, i) => ( + onAssetSelected(i)} + /> + )) + : accountAssets.map((item, i) => { + return ( + onAssetSelected(i)} + /> + ); + })} +
+ +
+ +
); }; -interface IAssetProps{ - onClick:() => void; - isSelected:boolean +interface IAssetProps { + onClick: () => void; + isSelected: boolean; + tx?: RecoveryTx; + isLoading: boolean; } - -const AssetItem = ({onClick, isSelected}:IAssetProps) => { - return onClick()} - className={`${isSelected ? "bg-base-200" : ""} ${styles.assetItem}`} -> -
- -
-
-

Name

- ID -
-
-} +const AssetItem = ({ onClick, isSelected, tx, isLoading }: IAssetProps) => { + const getSubtitleTitle = () => { + if (!tx) { + return ""; + } + if (["erc1155", "erc721"].indexOf(tx.type) != -1) { + //@ts-ignore + return `Token ID: ${tx.tokenId!}`; + } + if (tx.type === "erc20") { + //@ts-ignore + return tx.value; + } + return ""; + }; + const getTitle = () => { + if (!tx) { + return ""; + } + if (tx.type === "erc20") { + //@ts-ignore + return tx.symbol; + } + return tx.info; + }; + return ( + onClick()} + className={`${isSelected ? "bg-base-200" : ""} ${styles.assetItem} ${isLoading ? styles.loading : ""}`} + > +
+ +
+
+

{getTitle()}

+ {getSubtitleTitle()} +
+
+ ); +}; diff --git a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css index ebadd77..6505223 100644 --- a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css +++ b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css @@ -32,19 +32,24 @@ .assetList{ width: 100%; max-height: calc(100vh - 400px); + height: calc(100vh - 400px); overflow: auto; margin: 36px 0; } .button{ - width: 200px; + width: 230px; margin: 0 auto; padding: 0px 48px; height: 40px; font-size: 16px; -font-style: normal; -font-weight: 700; -line-height: normal; + font-style: normal; + font-weight: 700; + line-height: normal; + border: 1px solid; +} +.button:hover{ + border: 1px solid; } .logo{ @@ -58,4 +63,31 @@ line-height: normal; flex-direction: column; justify-content: center; margin-left:16px; -} \ No newline at end of file +} + +.loader{ + height: 94px; + display: flex; + justify-content: center; + align-items: center; +} + +.loading span{ + background-color:#3a4862; + width: 100px; + height: 24px; +} +.loading h3{ + background-color:#3a4862; + width: 130px; + height: 24px; +} + +.loading{ + animation: loading 1s infinite; +} + +@keyframes loading { + from {opacity: 0.3;} + to {opacity: 0.8;} + } \ No newline at end of file diff --git a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx index b618596..e15c104 100644 --- a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx +++ b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx @@ -1,38 +1,47 @@ -import React from "react"; -import Image from "next/image"; -import IllustrationSvg from "../../../public/assets/flashbotRecovery/logo.svg"; +import React, { useState } from "react"; import styles from "./hackedAddressStep.module.css"; +import { isAddress } from "ethers/lib/utils"; import { AnimatePresence, motion } from "framer-motion"; -import { useLocalStorage } from "usehooks-ts"; -import { AddressInput, RainbowKitCustomConnectButton } from "~~/components/scaffold-eth"; +import { AddressInput } from "~~/components/scaffold-eth"; interface IProps { isVisible: boolean; + onSubmit: (address: string) => void; } -export const HackedAddressStep = ({ isVisible }: IProps) => { - const [hackedAddress, setHackedAddress] = useLocalStorage("hackedAddress", ""); +export const HackedAddressStep = ({ isVisible, onSubmit }: IProps) => { + + if(!isVisible){ + return <> + } + + const [hackedAddress, setHackedAddress] = useState(""); return ( - - {isVisible && ( - - - - - - )} - + { + e.preventDefault(); + if (!isAddress(hackedAddress)) { + alert("Given hacked address is not a valid address"); + return; + } + onSubmit(hackedAddress); + }} + > + + + + ); }; diff --git a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css index 3a85528..cc45b58 100644 --- a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css +++ b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css @@ -16,6 +16,7 @@ margin-bottom: 12px; } .container > div{ border-radius: 4px; + padding: 4px; } .button{ width: 200px; diff --git a/packages/nextjs/components/flashbotRecovery/Layout/Layout.tsx b/packages/nextjs/components/flashbotRecovery/Layout/Layout.tsx index 3434278..e1d1c4f 100644 --- a/packages/nextjs/components/flashbotRecovery/Layout/Layout.tsx +++ b/packages/nextjs/components/flashbotRecovery/Layout/Layout.tsx @@ -21,28 +21,30 @@ export const Layout = ({ children, stepActive }: IProps) => {
diff --git a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css index 508e40a..1041060 100644 --- a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css +++ b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css @@ -19,6 +19,7 @@ display: flex; height: 42px; max-width: 600px; + width: 90%; margin: 0 auto; cursor: pointer; border-radius: 4px; @@ -39,7 +40,8 @@ font-weight: 500; } .assetList{ width: 100%; - max-height: calc(100vh - 400px); + max-height: calc(100vh - 500px); + height: calc(100vh - 500px); overflow: auto; margin: 36px 0; margin-bottom: 0; @@ -73,7 +75,7 @@ font-weight: 500; margin-right: 16px; } -.logoContainer{ +.close{ display: flex; flex-direction: column; justify-content: center; diff --git a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx index 52d0a8c..d71e732 100644 --- a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx +++ b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx @@ -1,77 +1,84 @@ -import React, { useState } from "react"; -import Image from "next/image"; -import LogoSvg from "../../../public/assets/flashbotRecovery/logo.svg"; +import React, { Dispatch, SetStateAction } from "react"; import styles from "./transactionBundleStep.module.css"; import { AnimatePresence, motion } from "framer-motion"; +import { RecoveryTx } from "~~/types/business"; interface IProps { isVisible: boolean; + clear:() => void; + transactions: RecoveryTx[]; + onAddMore:() => void; + modifyTransactions:Dispatch> } -export const TransactionBundleStep = ({ isVisible }: IProps) => { - const [selectedAssets, setSelectedAssets] = useState([]); - const list = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; +export const TransactionBundleStep = ({ clear,onAddMore, isVisible, transactions, modifyTransactions }: IProps) => { + if (!isVisible) { + return <>; + } - const onAssetSelected = (i: number) => { - const currentIndex = selectedAssets.indexOf(i); - let newAssets: number[] = []; - if (currentIndex === -1) { - newAssets.push(i); - newAssets.push(...selectedAssets); - } else { - newAssets = selectedAssets.filter(item => item !== i); - } - setSelectedAssets(newAssets); + + const removeUnsignedTx = (txId: number) => { + modifyTransactions((prev: RecoveryTx[]) => { + if (txId < 0 || txId > prev.length) { + return prev.filter(a => a); + } + delete prev[txId]; + + const newUnsignedTxArr = prev.filter(a => a); + return newUnsignedTxArr; + }); }; + return ( - - {isVisible && ( - -

Your transactions

-
- {list.map((item, i) => ( - onAssetSelected(i)} - title={i%2 === 0 ? "Custom call (transfer) to 0x24923bah971904020q9q98198y83": "NFT recovery for tokenID 1"} - /> - ))} -
- Clear all -
- -
- -
- )} -
+ +

Your transactions

+
+ {transactions.map((item, i) => { + return removeUnsignedTx(i)} tx={item} />; + })} +
+ clear()}>Clear all +
+ +
+ +
); }; interface ITransactionProps { onDelete: () => void; - isSelected: boolean; - title: string; + tx?: RecoveryTx; } -const TransactionItem = ({ onDelete, title }: ITransactionProps) => { +const TransactionItem = ({ onDelete, tx }: ITransactionProps) => { + + + const getTitle = () => { + if (!tx) { + return ""; + } + if (["erc1155", "erc721"].indexOf(tx.type) != -1) { + //@ts-ignore + return `${tx.info} (${tx.tokenId!})`; + } + if (tx.type === "erc20") { + //@ts-ignore + return `${tx.value} ${tx.symbol} `; + } + return tx.info; + }; + return ( onDelete()} className={`${styles.assetItem} bg-base-200 text-secondary-content`} >
-

{title}

+

{getTitle()}

-
X
+
onDelete()}>X
); }; diff --git a/packages/nextjs/hooks/flashbotRecoveryBundle/useAutodetectAssets.ts b/packages/nextjs/hooks/flashbotRecoveryBundle/useAutodetectAssets.ts new file mode 100644 index 0000000..d2d57a6 --- /dev/null +++ b/packages/nextjs/hooks/flashbotRecoveryBundle/useAutodetectAssets.ts @@ -0,0 +1,327 @@ +import React, { useState } from "react"; +import { Alchemy, AssetTransfersCategory, AssetTransfersResult, Network } from "alchemy-sdk"; +import { BigNumber, ethers } from "ethers"; +import { usePublicClient } from "wagmi"; +import { + AutoDetectedERC20Info, + AutoDetectedERC721Info, + AutoDetectedERC1155Info, + ERC20Tx, + ERC721Tx, + ERC1155Tx, + RecoveryTx, +} from "~~/types/business"; +import { ERC20_ABI, ERC721_ABI, ERC1155_ABI } from "~~/utils/constants"; +import { getTargetNetwork } from "~~/utils/scaffold-eth"; + +const erc20Interface = new ethers.utils.Interface(ERC20_ABI); +const erc721Interface = new ethers.utils.Interface(ERC721_ABI); +const erc1155Interface = new ethers.utils.Interface(ERC1155_ABI); + +interface IProps { + hackedAddress: string; + safeAddress: string; +} + +export const useAutodetectAssets = () => { + const targetNetwork = getTargetNetwork(); + const [alchemy] = useState( + new Alchemy({ + apiKey: "v_x1FpS3QsTUZJK3leVsHJ_ircahJ1nt", + network: targetNetwork.network == "goerli" ? Network.ETH_GOERLI : Network.ETH_MAINNET, + }), + ); + const publicClient = usePublicClient({ chainId: targetNetwork.id }); + + const fetchAllAssetTransfersOfHackedAccount = async (hackedAddress: string) => + ( + await Promise.all([ + alchemy.core.getAssetTransfers({ + fromAddress: hackedAddress, + excludeZeroValue: true, + category: [AssetTransfersCategory.ERC20, AssetTransfersCategory.ERC721, AssetTransfersCategory.ERC1155], + }), + alchemy.core.getAssetTransfers({ + toAddress: hackedAddress, + excludeZeroValue: true, + category: [AssetTransfersCategory.ERC20, AssetTransfersCategory.ERC721, AssetTransfersCategory.ERC1155], + }), + ]) + ) + .map(res => res.transfers) + .flat(); + + const getAutodetectedAssets = async ({ hackedAddress, safeAddress }: IProps) => { + if (!ethers.utils.isAddress(hackedAddress)) { + return; + } + if (!alchemy) { + alert("Seems Alchemy API rate limit has been reached. Contact irbozk@gmail.com"); + return; + } + + const erc20transfers: AssetTransfersResult[] = [], + erc721transfers: AssetTransfersResult[] = [], + erc1155transfers: AssetTransfersResult[] = []; + + try { + (await fetchAllAssetTransfersOfHackedAccount(hackedAddress)).forEach(tx => { + if (tx.category == AssetTransfersCategory.ERC20) { + erc20transfers.push(tx); + } else if (tx.category == AssetTransfersCategory.ERC721) { + erc721transfers.push(tx); + } else if (tx.category == AssetTransfersCategory.ERC1155) { + erc1155transfers.push(tx); + } + }); + + // Classify the fetched transfers + + const erc20contracts = Array.from( + new Set( + erc20transfers.filter(tx => tx.rawContract.address != null).map(tx => tx.rawContract.address! as string), + ), + ); + + const erc721contractsAndTokenIds = erc721transfers.reduce( + (acc, tx) => { + const assetContractAddress = tx.rawContract.address; + const assetTokenId = tx.erc721TokenId; + + if (!assetContractAddress || !assetTokenId) { + return acc; + } + + if (!(assetContractAddress in acc)) { + acc[assetContractAddress] = new Set(); + } + + acc[assetContractAddress].add(assetTokenId); + return acc; + }, + {} as { + [address: string]: Set; + }, + ); + + const erc1155contractsAndTokenIds = erc1155transfers.reduce( + (acc, tx) => { + const assetContractAddress = tx.rawContract.address; + const assetMetadata = tx.erc1155Metadata; + + if (!assetContractAddress || !assetMetadata) { + return acc; + } + + if (!(assetContractAddress in acc)) { + acc[assetContractAddress] = new Set(); + } + + assetMetadata.map(meta => meta.tokenId).forEach(tokenId => acc[assetContractAddress].add(tokenId)); + return acc; + }, + {} as { + [address: string]: Set; + }, + ); + + // Now get the balances & owned NFTs + + const erc20BalancePromises = erc20contracts.map(async erc20contract => { + const balance = (await publicClient.readContract({ + address: erc20contract as `0x${string}`, + abi: ERC20_ABI, + functionName: "balanceOf", + args: [hackedAddress], + })) as string; + if (!balance || balance.toString() == "0") { + return []; + } + return [erc20contract, balance.toString()]; + }); + + const erc721OwnershipPromises = Object.keys(erc721contractsAndTokenIds).map(async erc721Contract => { + const ownedTokenIds = await Promise.all( + Array.from(erc721contractsAndTokenIds[erc721Contract]).map(async tokenId => { + const ownerOfGivenTokenId = await publicClient.readContract({ + address: erc721Contract as `0x${string}`, + abi: ERC721_ABI, + functionName: "ownerOf", + args: [BigNumber.from(tokenId)], + }); + if (!ownerOfGivenTokenId || ownerOfGivenTokenId != hackedAddress) { + return undefined; + } + return tokenId; + }), + ); + const ownedTokenIdsFiltered = ownedTokenIds.filter(tokenId => tokenId != undefined) as string[]; + if (ownedTokenIdsFiltered.length == 0) { + return []; + } + return [erc721Contract, ownedTokenIdsFiltered]; + }); + + const erc1155OwnershipPromises = Object.keys(erc1155contractsAndTokenIds).map(async erc1155Contract => { + const tokenIdsWithinContract = Array.from(erc1155contractsAndTokenIds[erc1155Contract]); + const tokenIdBalances = (await publicClient.readContract({ + address: erc1155Contract as `0x${string}`, + abi: ERC1155_ABI, + functionName: "balanceOfBatch", + args: [Array(tokenIdsWithinContract.length).fill(hackedAddress), tokenIdsWithinContract], + })) as bigint[]; + + const tokenIdsAndBalances: string[][] = []; + for (let i = 0; i < tokenIdBalances.length; i++) { + if (tokenIdBalances[i] == 0n) { + continue; + } + tokenIdsAndBalances.push([tokenIdsWithinContract[i], tokenIdBalances[i].toString()]); + } + if (tokenIdsAndBalances.length == 0) { + return []; + } + + return [erc1155Contract, Object.fromEntries(tokenIdsAndBalances)]; + }); + + // Await all the promises + + const { erc20ContractsAndBalances, erc721ContractsAndOwnedTokens, erc1155ContractsAndTokenIdsWithBalances } = + await Promise.all([ + (await Promise.all(erc20BalancePromises)).filter(a => a.length > 0), + (await Promise.all(erc721OwnershipPromises)).filter(a => a.length > 0), + (await Promise.all(erc1155OwnershipPromises)).filter(a => a.length > 0), + ]).then(([erc20res, erc721res, erc1155res]) => { + return { + erc20ContractsAndBalances: Object.fromEntries(erc20res) as AutoDetectedERC20Info, + erc721ContractsAndOwnedTokens: Object.fromEntries(erc721res) as AutoDetectedERC721Info, + erc1155ContractsAndTokenIdsWithBalances: Object.fromEntries(erc1155res) as AutoDetectedERC1155Info, + }; + }); + + // Fetch token symbols and save results + + const autoDetectedErc20Txs: ERC20Tx[] = await Promise.all( + Object.entries(erc20ContractsAndBalances).map(async ([erc20contract, erc20balance]) => { + let tokenSymbol = "???"; + try { + tokenSymbol = (await publicClient.readContract({ + address: erc20contract as `0x${string}`, + abi: ERC20_ABI, + functionName: "symbol", + args: [], + })) as string; + } catch (e) { + /* ignore */ + } + + const newErc20tx: ERC20Tx = { + type: "erc20", + info: `ERC20 - ${tokenSymbol != "???" ? `${tokenSymbol}` : `${erc20contract}`}`, + symbol: tokenSymbol, + amount: erc20balance, + toSign: { + from: hackedAddress as `0x${string}`, + to: erc20contract as `0x${string}`, + data: erc20Interface.encodeFunctionData("transfer", [ + safeAddress, + BigNumber.from(erc20balance), + ]) as `0x${string}`, + }, + }; + return newErc20tx; + }), + ); + + const autoDetectedErc721Txs: ERC721Tx[] = ( + await Promise.all( + Object.entries(erc721ContractsAndOwnedTokens).map(async ([erc721contract, ownedTokenIds]) => { + let tokenSymbol = "???"; + try { + tokenSymbol = (await publicClient.readContract({ + address: erc721contract as `0x${string}`, + abi: ERC721_ABI, + functionName: "symbol", + args: [], + })) as string; + } catch (e) { + /* ignore */ + } + + const newErc721txs: ERC721Tx[] = ownedTokenIds.map(tokenId => { + const newErc721tx: ERC721Tx = { + type: "erc721", + info: `ERC721 - ${tokenSymbol != "???" ? `${tokenSymbol}` : `${erc721contract}`}`, + symbol: tokenSymbol, + tokenId: parseInt(tokenId).toString(), + toSign: { + from: hackedAddress as `0x${string}`, + to: erc721contract as `0x${string}`, + data: erc721Interface.encodeFunctionData("transferFrom", [ + hackedAddress, + safeAddress, + BigNumber.from(tokenId), + ]) as `0x${string}`, + }, + }; + return newErc721tx; + }); + return newErc721txs; + }), + ) + ).flat(); + + const autoDetectedErc1155Txs: ERC1155Tx[] = await Promise.all( + Object.entries(erc1155ContractsAndTokenIdsWithBalances).map(async ([erc1155contract, tokenIdsAndBalances]) => { + let uri = "???"; + try { + uri = (await publicClient.readContract({ + address: erc1155contract as `0x${string}`, + abi: ERC1155_ABI, + functionName: "uri", + args: [0], + })) as string; + } catch (e) { + /* ignore */ + } + + const tokenIds = Object.keys(tokenIdsAndBalances); + const balances: string[] = []; + for (let i = 0; i < tokenIds.length; i++) { + balances.push(tokenIdsAndBalances[tokenIds[i]]); + } + + const newErc1155Tx: ERC1155Tx = { + type: "erc1155", + info: `ERC1155 - ${uri != "???" ? `${uri}` : `${erc1155contract}`}`, + uri: "changeme", + tokenIds: tokenIds, + amounts: balances, + toSign: { + from: hackedAddress as `0x${string}`, + to: erc1155contract as `0x${string}`, + data: erc1155Interface.encodeFunctionData("safeBatchTransferFrom", [ + hackedAddress, + safeAddress, + tokenIds, + balances, + ethers.constants.HashZero, + ]) as `0x${string}`, + }, + }; + return newErc1155Tx; + }), + ); + const result: RecoveryTx[] = [...autoDetectedErc20Txs, ...autoDetectedErc721Txs, ...autoDetectedErc1155Txs]; + return result; + // TODO FRAN await estimateTotalGasPrice(unsignedTxsInitializationVector); + } catch (e) { + console.error(`Error fetching assets of hacked account: ${e}`); + } + }; + + return { + getAutodetectedAssets, + }; +}; From dd76dd39d1c57780f520f5a72e2d6f05d07a6bc5 Mon Sep 17 00:00:00 2001 From: Fran Date: Mon, 21 Aug 2023 01:38:43 +0200 Subject: [PATCH 11/85] use cutom button --- .../AssetSelectionStep/AssetSelectionStep.tsx | 7 ++-- .../CustomButton/CustomButton.tsx | 13 +++++++ .../CustomButton/customButton.module.css | 11 ++++++ .../CustomPortal/CustomPortal.tsx | 38 +++++++++---------- .../HackedAddressStep/HackedAddressStep.tsx | 38 +++++++++---------- .../transactionBundleStep.module.css | 11 ------ .../transactionBundleStep.tsx | 27 ++++++------- 7 files changed, 77 insertions(+), 68 deletions(-) create mode 100644 packages/nextjs/components/flashbotRecovery/CustomButton/CustomButton.tsx create mode 100644 packages/nextjs/components/flashbotRecovery/CustomButton/customButton.module.css diff --git a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx index 355eb43..4b0f464 100644 --- a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx +++ b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx @@ -5,6 +5,7 @@ import styles from "./assetSelectionStep.module.css"; import { motion } from "framer-motion"; import { useAutodetectAssets } from "~~/hooks/flashbotRecoveryBundle/useAutodetectAssets"; import { RecoveryTx } from "~~/types/business"; +import { CustomButton } from "../CustomButton/CustomButton"; interface IProps { isVisible: boolean; @@ -79,11 +80,9 @@ export const AssetSelectionStep = ({ isVisible, onSubmit, hackedAddress, safeAdd ); })}
- + ({})} />
- + onAddAssetsClick()} /> ); }; diff --git a/packages/nextjs/components/flashbotRecovery/CustomButton/CustomButton.tsx b/packages/nextjs/components/flashbotRecovery/CustomButton/CustomButton.tsx new file mode 100644 index 0000000..6fab65f --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/CustomButton/CustomButton.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import styles from "./customButton.module.css"; + +interface IProps{ + text:string; + onClick:() => void; + type:"accent"|"primary" +} +export const CustomButton = ({text, onClick, type}:IProps) => { + return ( + + ) +} diff --git a/packages/nextjs/components/flashbotRecovery/CustomButton/customButton.module.css b/packages/nextjs/components/flashbotRecovery/CustomButton/customButton.module.css new file mode 100644 index 0000000..ad3de56 --- /dev/null +++ b/packages/nextjs/components/flashbotRecovery/CustomButton/customButton.module.css @@ -0,0 +1,11 @@ +.button{ + width: 230px; + margin: 0 auto; + padding: 0px 48px; + height: 40px; + font-size: 16px; + font-style: normal; + font-weight: 700; + line-height: normal; + border: 1px solid; +} \ No newline at end of file diff --git a/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx b/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx index f90fd55..1b33001 100644 --- a/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx +++ b/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx @@ -1,21 +1,22 @@ import { useEffect, useState } from "react"; import Image from "next/image"; -import styles from "./customPortal.module.css"; -import { createPortal } from "react-dom"; import CloseSvg from "../../../public/assets/flashbotRecovery/close.svg"; +import { CustomButton } from "../CustomButton/CustomButton"; +import styles from "./customPortal.module.css"; import { motion } from "framer-motion"; +import { createPortal } from "react-dom"; interface IProps { title: string; image?: string; video?: string; description: string; - button?:{ - text:string, - action:() => void - } + button?: { + text: string; + action: () => void; + }; } -export const CustomPortal = ({ title, image, video, description, button}: IProps) => { +export const CustomPortal = ({ title, image, video, description, button }: IProps) => { const [mounted, setMounted] = useState(false); useEffect(() => { @@ -30,24 +31,23 @@ export const CustomPortal = ({ title, image, video, description, button}: IProps return mounted ? createPortal( - +
setMounted(false)}> {" "} {""}
- - -

{title}

- {!!image ? {""} : <>} - {!!video ?
, diff --git a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx index e15c104..b8ca913 100644 --- a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx +++ b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/HackedAddressStep.tsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import { CustomButton } from "../CustomButton/CustomButton"; import styles from "./hackedAddressStep.module.css"; import { isAddress } from "ethers/lib/utils"; import { AnimatePresence, motion } from "framer-motion"; @@ -9,27 +10,14 @@ interface IProps { onSubmit: (address: string) => void; } export const HackedAddressStep = ({ isVisible, onSubmit }: IProps) => { - - if(!isVisible){ - return <> + if (!isVisible) { + return <>; } - + const [hackedAddress, setHackedAddress] = useState(""); return ( - { - e.preventDefault(); - if (!isAddress(hackedAddress)) { - alert("Given hacked address is not a valid address"); - return; - } - onSubmit(hackedAddress); - }} - > + @@ -39,9 +27,17 @@ export const HackedAddressStep = ({ isVisible, onSubmit }: IProps) => { placeholder={"0xcEBD023e3a...F7fa035bbf52e6"} onChange={setHackedAddress} /> - - + { + if (!isAddress(hackedAddress)) { + alert("Given hacked address is not a valid address"); + return; + } + onSubmit(hackedAddress); + }} + /> +
); }; diff --git a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css index 1041060..2f71b55 100644 --- a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css +++ b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.module.css @@ -47,17 +47,6 @@ font-weight: 500; margin-bottom: 0; } -.button{ - width: 230px; - margin: 0 auto; - padding: 0px 48px; - height: 40px; - font-size: 16px; - font-style: normal; - font-weight: 700; - line-height: normal; - border: 1px solid; -} .clear{ text-decoration: underline; width: 230px; diff --git a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx index d71e732..b16c484 100644 --- a/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx +++ b/packages/nextjs/components/flashbotRecovery/TransactionBundleStep/transactionBundleStep.tsx @@ -1,21 +1,21 @@ import React, { Dispatch, SetStateAction } from "react"; +import { CustomButton } from "../CustomButton/CustomButton"; import styles from "./transactionBundleStep.module.css"; import { AnimatePresence, motion } from "framer-motion"; import { RecoveryTx } from "~~/types/business"; interface IProps { isVisible: boolean; - clear:() => void; + clear: () => void; transactions: RecoveryTx[]; - onAddMore:() => void; - modifyTransactions:Dispatch> + onAddMore: () => void; + modifyTransactions: Dispatch>; } -export const TransactionBundleStep = ({ clear,onAddMore, isVisible, transactions, modifyTransactions }: IProps) => { +export const TransactionBundleStep = ({ clear, onAddMore, isVisible, transactions, modifyTransactions }: IProps) => { if (!isVisible) { return <>; } - const removeUnsignedTx = (txId: number) => { modifyTransactions((prev: RecoveryTx[]) => { if (txId < 0 || txId > prev.length) { @@ -28,7 +28,6 @@ export const TransactionBundleStep = ({ clear,onAddMore, isVisible, transactions }); }; - return (

Your transactions

@@ -37,11 +36,13 @@ export const TransactionBundleStep = ({ clear,onAddMore, isVisible, transactions return removeUnsignedTx(i)} tx={item} />; })} - clear()}>Clear all + clear()}> + Clear all +
- + onAddMore()} />
- + ({})} />
); }; @@ -52,8 +53,6 @@ interface ITransactionProps { } const TransactionItem = ({ onDelete, tx }: ITransactionProps) => { - - const getTitle = () => { if (!tx) { return ""; @@ -68,7 +67,7 @@ const TransactionItem = ({ onDelete, tx }: ITransactionProps) => { } return tx.info; }; - + return ( {

{getTitle()}

-
onDelete()}>X
+
onDelete()}> + X +
); }; From 3aa32191d8ec27b9998015a267c722ff3b7e995b Mon Sep 17 00:00:00 2001 From: Fran Date: Mon, 21 Aug 2023 01:40:26 +0200 Subject: [PATCH 12/85] remove button extra styles --- .../assetSelectionStep.module.css | 15 --------------- .../CustomButton/customButton.module.css | 5 ++++- .../CustomPortal/customPortal.module.css | 9 --------- .../hackedAddressStep.module.css | 11 ----------- 4 files changed, 4 insertions(+), 36 deletions(-) diff --git a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css index 6505223..fea315f 100644 --- a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css +++ b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/assetSelectionStep.module.css @@ -37,21 +37,6 @@ margin: 36px 0; } -.button{ - width: 230px; - margin: 0 auto; - padding: 0px 48px; - height: 40px; - font-size: 16px; - font-style: normal; - font-weight: 700; - line-height: normal; - border: 1px solid; -} -.button:hover{ - border: 1px solid; -} - .logo{ width: 60px; height: 60px; diff --git a/packages/nextjs/components/flashbotRecovery/CustomButton/customButton.module.css b/packages/nextjs/components/flashbotRecovery/CustomButton/customButton.module.css index ad3de56..fe8a450 100644 --- a/packages/nextjs/components/flashbotRecovery/CustomButton/customButton.module.css +++ b/packages/nextjs/components/flashbotRecovery/CustomButton/customButton.module.css @@ -8,4 +8,7 @@ font-weight: 700; line-height: normal; border: 1px solid; -} \ No newline at end of file +} +.button:hover{ + border: 1px solid; +} diff --git a/packages/nextjs/components/flashbotRecovery/CustomPortal/customPortal.module.css b/packages/nextjs/components/flashbotRecovery/CustomPortal/customPortal.module.css index 6f0ad77..85fa08a 100644 --- a/packages/nextjs/components/flashbotRecovery/CustomPortal/customPortal.module.css +++ b/packages/nextjs/components/flashbotRecovery/CustomPortal/customPortal.module.css @@ -31,15 +31,6 @@ flex-shrink: 0; margin-bottom: 56px; } -.button{ - width: 230px; - margin: 0 auto; - font-size: 16px; - font-style: normal; - font-weight: 700; - line-height: normal; - border: 1px solid; -} .close{ align-self: flex-end; diff --git a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css index cc45b58..540b8c6 100644 --- a/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css +++ b/packages/nextjs/components/flashbotRecovery/HackedAddressStep/hackedAddressStep.module.css @@ -17,15 +17,4 @@ margin-bottom: 12px; .container > div{ border-radius: 4px; padding: 4px; -} -.button{ - width: 200px; - margin: 0 auto; - margin-top: 40px; - padding: 0px 48px; - height: 40px; - font-size: 16px; -font-style: normal; -font-weight: 700; -line-height: normal; } \ No newline at end of file From 1eba0f75206183e0b0a133822697fc44ad1a68c2 Mon Sep 17 00:00:00 2001 From: Fran Date: Mon, 21 Aug 2023 02:45:01 +0200 Subject: [PATCH 13/85] add gas estimation --- .../AssetSelectionStep/AssetSelectionStep.tsx | 4 +- .../CustomButton/CustomButton.tsx | 4 +- .../CustomPortal/CustomPortal.tsx | 2 +- .../transactionBundleStep.module.css | 8 +- .../transactionBundleStep.tsx | 99 ++++++++++++++++++- .../useAutodetectAssets.ts | 1 - .../public/assets/flashbotRecovery/gas.svg | 9 ++ packages/nextjs/styles/globals.css | 6 +- 8 files changed, 118 insertions(+), 15 deletions(-) create mode 100644 packages/nextjs/public/assets/flashbotRecovery/gas.svg diff --git a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx index 4b0f464..4561bb2 100644 --- a/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx +++ b/packages/nextjs/components/flashbotRecovery/AssetSelectionStep/AssetSelectionStep.tsx @@ -80,9 +80,9 @@ export const AssetSelectionStep = ({ isVisible, onSubmit, hackedAddress, safeAdd ); })} - ({})} /> + ({})} />
- onAddAssetsClick()} /> + onAddAssetsClick()} /> ); }; diff --git a/packages/nextjs/components/flashbotRecovery/CustomButton/CustomButton.tsx b/packages/nextjs/components/flashbotRecovery/CustomButton/CustomButton.tsx index 6fab65f..0d24f89 100644 --- a/packages/nextjs/components/flashbotRecovery/CustomButton/CustomButton.tsx +++ b/packages/nextjs/components/flashbotRecovery/CustomButton/CustomButton.tsx @@ -4,10 +4,10 @@ import styles from "./customButton.module.css"; interface IProps{ text:string; onClick:() => void; - type:"accent"|"primary" + type:"btn-accent"|"btn-primary" } export const CustomButton = ({text, onClick, type}:IProps) => { return ( - + ) } diff --git a/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx b/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx index 1b33001..8d65570 100644 --- a/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx +++ b/packages/nextjs/components/flashbotRecovery/CustomPortal/CustomPortal.tsx @@ -47,7 +47,7 @@ export const CustomPortal = ({ title, image, video, description, button }: IProp {!!image ? {""} : <>} {!!video ?