From acc9ac04f8e6b366ff09cb982ef0f310725e36be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20Eren?= Date: Mon, 26 Aug 2024 15:52:27 +0300 Subject: [PATCH 1/9] feat: header & wallet (#24) * feat: Header * feat: header wallet connection * feat: wallet sidebar * feat: Wallet Sidebar actions --------- Co-authored-by: lanaivina <31368580+lana-shanghai@users.noreply.github.com> --- client/src/components/Button/index.tsx | 8 ++ .../components/ConnectWalletModal/index.tsx | 65 +++++++++++ client/src/components/Header/index.tsx | 105 +++++++++++++++++- client/src/components/WalletSidebar/index.tsx | 104 +++++++++++++++++ client/src/pages/Swap.tsx | 2 +- client/src/theme/colors.ts | 4 +- client/src/theme/components/icons.tsx | 76 +++++++++++++ client/src/theme/index.tsx | 9 ++ 8 files changed, 370 insertions(+), 3 deletions(-) create mode 100644 client/src/components/ConnectWalletModal/index.tsx create mode 100644 client/src/components/WalletSidebar/index.tsx diff --git a/client/src/components/Button/index.tsx b/client/src/components/Button/index.tsx index 644f595..a6fcef3 100644 --- a/client/src/components/Button/index.tsx +++ b/client/src/components/Button/index.tsx @@ -28,3 +28,11 @@ export const OutlineButton = styled.button` border: 1px solid ${({ theme }) => theme.white}; color: ${({ theme }) => theme.white}; ` + +export const ConnectButton = styled(PrimaryButton)` + width: auto; + padding: 14px 32px; + background: linear-gradient(360deg, #202a31 0%, #28353e 100%); + color: ${({ theme }) => theme.neutral1}; + font-size: 16px; +` diff --git a/client/src/components/ConnectWalletModal/index.tsx b/client/src/components/ConnectWalletModal/index.tsx new file mode 100644 index 0000000..ebceaa7 --- /dev/null +++ b/client/src/components/ConnectWalletModal/index.tsx @@ -0,0 +1,65 @@ +import { useConnect } from '@starknet-react/core' +import { ThemedText } from 'src/theme/components' +import styled from 'styled-components' + +import { Column, Row } from '../Flex' + +const Container = styled(Column)` + width: 300px; + align-items: flex-start; + padding: 16px; + background-color: ${({ theme }) => theme.bg2}; + border: 1px solid ${({ theme }) => theme.border}; + border-radius: 20px; + box-shadow: 0px 4px 4px 4px rgba(0, 0, 0, 0.3), 0px 8px 12px 10px rgba(0, 0, 0, 0.15); +` + +const ConnectorsList = styled(Column)` + width: 100%; + + :first-child { + border-top-left-radius: 12px; + border-top-right-radius: 12px; + } + + :last-child { + border-bottom-left-radius: 12px; + border-bottom-right-radius: 12px; + } +` + +const ConnectorCard = styled(Row)` + width: 100%; + padding: 12px; + background-color: ${({ theme }) => theme.bg3}; + border: none; + outline: none; + cursor: pointer; + + img { + width: 32px; + height: 32px; + } +` + +export const ConnectWalletModal = (props: React.ComponentPropsWithoutRef) => { + const { connect, connectors } = useConnect() + + return ( + + Connect wallet + + + {connectors + .filter((connector) => connector.available()) + .map((connector) => ( + connect({ connector })}> + {connector.name} + + {connector.name} + + ))} + + + ) +} diff --git a/client/src/components/Header/index.tsx b/client/src/components/Header/index.tsx index 86609de..da4986b 100644 --- a/client/src/components/Header/index.tsx +++ b/client/src/components/Header/index.tsx @@ -1,3 +1,106 @@ +import { useAccount } from '@starknet-react/core' +import { useState } from 'react' +import { NavLink } from 'react-router-dom' +import { ThemedText } from 'src/theme/components' +import { Logo } from 'src/theme/components/icons' +import styled from 'styled-components' + +import { ConnectButton } from '../Button' +import { ConnectWalletModal } from '../ConnectWalletModal' +import { Row } from '../Flex' +import WalletSidebar from '../WalletSidebar' + +const Container = styled(Row)` + justify-content: space-between; + padding: 24px 32px; +` + +const Link = styled(ThemedText.BodyPrimary)` + color: rgba(255, 255, 255, 0.7); + font-weight: 500; + font-size: 18px; + text-decoration: none; + + &.active { + color: ${({ theme }) => theme.neutral1}; + } +` + +const ConnectContainer = styled(Row)` + position: relative; +` + +const ConnectWalletDropdown = styled(ConnectWalletModal)` + position: absolute; + top: calc(100% + 16px); + right: 0; +` + +const AccountChip = styled(Row)` + padding: 6px 8px; + background-color: ${({ theme }) => theme.bg3}; + border: none; + border-radius: 99px; + cursor: pointer; +` + +const AccountStatusIcon = styled.div` + width: 12px; + height: 12px; + background-color: ${({ theme }) => theme.green}; + border-radius: 12px; +` + export default function Header() { - return null + const [connectDropdownShown, setConnectDropdownShown] = useState(false) + const [walletSidebarShown, setWalletSidebarShown] = useState(false) + + const { address } = useAccount() + + const toggleConnectDropdown = () => { + setConnectDropdownShown((prev) => !prev) + } + + const showWalletSidebar = () => { + setWalletSidebarShown(true) + } + const hideWalletSidebar = () => { + setWalletSidebarShown(false) + } + + return ( + + + + + + + Swap + + + + Liquidity + + + + + {address ? ( + + + + + {address.slice(0, 6)}...{address.slice(-4)} + + + ) : ( + + Connect + + {connectDropdownShown && } + + )} + + {walletSidebarShown && } + + ) } diff --git a/client/src/components/WalletSidebar/index.tsx b/client/src/components/WalletSidebar/index.tsx new file mode 100644 index 0000000..76ddf6e --- /dev/null +++ b/client/src/components/WalletSidebar/index.tsx @@ -0,0 +1,104 @@ +import { useAccount, useDisconnect } from '@starknet-react/core' +import { Link } from 'react-router-dom' +import { ThemedText } from 'src/theme/components' +import { DoubleChevronRight, Logout, StarknetLogo, UserCheck } from 'src/theme/components/icons' +import styled from 'styled-components' + +import { Column, Row } from '../Flex' + +const Container = styled(Column)` + position: fixed; + top: 0; + right: 0; + width: 372px; + height: 100%; + padding: 8px; +` + +const Content = styled(Column)` + width: 100%; + height: 100%; + padding: 16px; + background-color: ${({ theme }) => theme.bg2}; + border: 1px solid ${({ theme }) => theme.border}; + border-radius: 20px; +` + +const WalletInfo = styled(Row)` + width: 100%; + justify-content: space-between; +` + +const CloseButton = styled.button` + color: rgba(240, 247, 244, 0.5); + background-color: transparent; + border: none; + cursor: pointer; +` + +const Links = styled(Column)` + width: 100%; +` + +const LinkItem = styled(Row)` + width: 100%; + gap: 10px; + padding: 12px 6px; + background-color: transparent; + border: none; + border-radius: 8px; + text-decoration: none; + cursor: pointer; + + &:hover { + background-color: ${({ theme }) => theme.bg3}; + box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.3), 0px 2px 6px 2px rgba(0, 0, 0, 0.15), + 0px 0.5px 0px 0px rgba(240, 247, 244, 0.1) inset; + } + + div { + color: ${({ theme }) => theme.neutral1}; + } +` + +type WalletSidebarProps = { + onClose?: () => void +} + +export default function WalletSidebar({ onClose }: WalletSidebarProps) { + const { address } = useAccount() + const { disconnect } = useDisconnect() + + if (!address) return + + return ( + + + + + + + {address.slice(0, 6)}...{address.slice(-4)} + + + + + + + + + + + + Registration + + + disconnect()}> + + Disconnect + + + + + ) +} diff --git a/client/src/pages/Swap.tsx b/client/src/pages/Swap.tsx index f28e7ce..8db6410 100644 --- a/client/src/pages/Swap.tsx +++ b/client/src/pages/Swap.tsx @@ -12,7 +12,7 @@ import { styled } from 'styled-components' const Layout = styled(Column)` margin: 0 auto; justify-content: center; - height: 100vh; + flex: 1; ` const Content = styled(Column)` diff --git a/client/src/theme/colors.ts b/client/src/theme/colors.ts index 9da0417..eeee35f 100644 --- a/client/src/theme/colors.ts +++ b/client/src/theme/colors.ts @@ -3,6 +3,7 @@ const colors = { white: '#FFFFFF', black: '#000000', + green: '#21C95E', neutral1_dark: '#ffffff', neutral2_dark: 'rgba(240, 247, 244, 0.5)', @@ -11,6 +12,7 @@ const colors = { const commonTheme = { white: colors.white, black: colors.black, + green: colors.green, accent1: '#FF3864', } @@ -19,7 +21,7 @@ export const darkTheme = { ...commonTheme, bg1: '#000000', - bg2: '#121216', + bg2: '#101519', bg3: '#181F25', surface: '#0D0D12', diff --git a/client/src/theme/components/icons.tsx b/client/src/theme/components/icons.tsx index a05f627..8ebcf9c 100644 --- a/client/src/theme/components/icons.tsx +++ b/client/src/theme/components/icons.tsx @@ -20,6 +20,55 @@ export const Starknet = (props: SVGProps) => ( ) +export const StarknetLogo = (props: SVGProps) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +) + export const ChevronDown = (props: SVGProps) => ( ( /> ) + +export const DoubleChevronRight = (props: SVGProps) => ( + + + +) + +export const UserCheck = (props: SVGProps) => ( + + + +) + +export const Logout = (props: SVGProps) => ( + + + +) diff --git a/client/src/theme/index.tsx b/client/src/theme/index.tsx index c0bc459..e985703 100644 --- a/client/src/theme/index.tsx +++ b/client/src/theme/index.tsx @@ -94,6 +94,15 @@ export const ThemedGlobalStyle = createGlobalStyle` padding: 0; } + html, body, #root { + height: 100%; + } + + #root { + display: flex; + flex-direction: column; + } + * { box-sizing: border-box; font-family: 'Inter'; From 0041830b2d0cf9c2d5ac9df3c394c0fdecd99a8f Mon Sep 17 00:00:00 2001 From: Chqrles Date: Wed, 28 Aug 2024 14:47:15 +0200 Subject: [PATCH 2/9] Update README.md --- README.md | 50 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 281f5a1..c3f8f17 100644 --- a/README.md +++ b/README.md @@ -39,18 +39,44 @@ The concept was initially conceived and developed by [ZKP2P](https://zkp2p.xyz) ## Roadmap -### Milestone 1 - Basic Proving Flow - -* basic flow - * [ ] Alice deposits 10 USDC to Escrow contract - * [ ] client establish MPC TLS connection with the Notary node - * [ ] client (Alice) generates dummy proof about account ownership with Circom on emulated Revolut data - * [ ] client (Bob) generates dummy proof about account ownership with Circom on emulated Revolut data - * [ ] client (Bob) generates dummy proof about transfer of funds with Circom on emulated Revolut data - * [ ] Notary node signs the proof generated by the client (Bob) - * [ ] client (Bob) receives the signed proof and calls the [Groth16 verifier](https://github.com/keep-starknet-strange/garaga/blob/main/src/cairo/src/groth16.cairo), passing the proof as calldata - * [ ] the TLS contract verifies the Notary node's signature and the correctness of the client (Bob) proof - * [ ] the Bob claims Alice's funds from the Escrow contract +### Milestone 01 - E2E flow without data verification +Tasks: + +- [ ] extension mockup +- [ ] client mockup +- [ ] extension UI +- [ ] client swap page UI +- [ ] client wallet mgmt UI +- [ ] client registation page UI +- [ ] relevant data detection from extension +- [ ] extension/client connection +- [ ] onchain registration +- [ ] onchain escrow + +### Milestone 02 - Offchain notarization and SNARK generation +Tasks: + +- [ ] Notary mgmt UI in extension +- [ ] 2PC-TLS with notary mgmt +- [ ] Prover commitment generation +- [ ] generation of the verification zk-SNARK + +### Milestone 03 - Onchain verification +Tasks: + +- [ ] zk-SNARK (groth16) verification with Garaga +- [ ] escrow assertions based on previous verification + +### Milestone 04 - Liquidity mgmt improved +Tasks: + +- [ ] Liquidity lock/unlock implementation to avoid onramp collusions +- [ ] Allow better granularity +- [ ] Liquidity mgmt UI in client +- [ ] Onchain Liquidity mgmt implementation + +### Milestone 05 - Notaries decentralisation +DVM could be an interesting solution to achieve this goal ## Flowchart 🎡 From bee91cc7ca6f8fd38093cd53e5380fa0ea3840c3 Mon Sep 17 00:00:00 2001 From: Bryan <62529683+BryanBorck@users.noreply.github.com> Date: Thu, 29 Aug 2024 11:15:48 -0300 Subject: [PATCH 3/9] feat: extension connection logic (#25) Co-authored-by: lanaivina <31368580+lana-shanghai@users.noreply.github.com> --- extension/package.json | 3 + extension/src/entries/Background/db.ts | 33 ++++++ extension/src/entries/Background/index.ts | 14 ++- extension/src/entries/Background/mutex.ts | 5 + extension/src/entries/Background/rpc.ts | 82 ++++++++++++++ extension/src/entries/Content/content.ts | 34 ++++++ extension/src/entries/Content/index.ts | 78 +++++++++++++ extension/src/entries/Content/rpc.ts | 102 +++++++++++++++++ extension/src/manifest.json | 23 ++-- extension/src/utils/promise.ts | 17 +++ extension/webpack.config.js | 2 + extension/yarn.lock | 127 +++++++++++++++++++++- 12 files changed, 506 insertions(+), 14 deletions(-) create mode 100644 extension/src/entries/Background/db.ts create mode 100644 extension/src/entries/Background/mutex.ts create mode 100644 extension/src/entries/Background/rpc.ts create mode 100644 extension/src/entries/Content/content.ts create mode 100644 extension/src/entries/Content/index.ts create mode 100644 extension/src/entries/Content/rpc.ts create mode 100644 extension/src/utils/promise.ts diff --git a/extension/package.json b/extension/package.json index c4bfd04..03a55d8 100644 --- a/extension/package.json +++ b/extension/package.json @@ -5,6 +5,8 @@ "lint": "eslint . --cache --ext .ts,.tsx" }, "dependencies": { + "async-mutex": "^0.5.0", + "level": "^8.0.1", "polished": "^4.2.2", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -15,6 +17,7 @@ "devDependencies": { "@craco/craco": "^7.1.0", "@svgr/webpack": "^8.1.0", + "@types/chrome": "^0.0.270", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.18", "@types/rebass": "^4.0.14", diff --git a/extension/src/entries/Background/db.ts b/extension/src/entries/Background/db.ts new file mode 100644 index 0000000..71b0218 --- /dev/null +++ b/extension/src/entries/Background/db.ts @@ -0,0 +1,33 @@ +import { Level } from 'level' + +import mutex from './mutex' + +const db = new Level('./ext-db', { + valueEncoding: 'json', +}) +const connectionDb = db.sublevel('connections', { + valueEncoding: 'json', +}) + +export async function setConnection(origin: string) { + if (await getConnection(origin)) return null + await connectionDb.put(origin, true) + return true +} + +export async function deleteConnection(origin: string) { + return mutex.runExclusive(async () => { + if (await getConnection(origin)) { + await connectionDb.del(origin) + } + }) +} + +export async function getConnection(origin: string) { + try { + const existing = await connectionDb.get(origin) + return existing + } catch (e) { + return null + } +} diff --git a/extension/src/entries/Background/index.ts b/extension/src/entries/Background/index.ts index 204438b..2e04c2b 100644 --- a/extension/src/entries/Background/index.ts +++ b/extension/src/entries/Background/index.ts @@ -1,4 +1,10 @@ -// eslint-disable-next-line import/no-unused-modules - -// @ts-ignore -chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch((error: any) => console.error(error)) +import { initRPC } from './rpc' +;(async () => { + try { + // @ts-ignore + chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch((error: any) => console.error(error)) + initRPC() + } catch (error) { + console.error('Error when initializing RPC:', error) + } +})() diff --git a/extension/src/entries/Background/mutex.ts b/extension/src/entries/Background/mutex.ts new file mode 100644 index 0000000..0833fad --- /dev/null +++ b/extension/src/entries/Background/mutex.ts @@ -0,0 +1,5 @@ +import { Mutex } from 'async-mutex' + +const mutex = new Mutex() + +export default mutex diff --git a/extension/src/entries/Background/rpc.ts b/extension/src/entries/Background/rpc.ts new file mode 100644 index 0000000..bd72a19 --- /dev/null +++ b/extension/src/entries/Background/rpc.ts @@ -0,0 +1,82 @@ +import { deferredPromise } from 'src/utils/promise' + +import { deleteConnection, getConnection, setConnection } from './db' + +export enum BackgroundActionType { + connect_request = 'connect_request', + disconnect_request = 'disconnect_request', + extract_data_request = 'extract_data_request', +} + +type BackgroundAction = { + type: BackgroundActionType + data?: any + meta?: any + error?: boolean +} + +export const initRPC = () => { + // @ts-ignore + chrome.runtime.onMessage.addListener((request: BackgroundAction, _sender, sendResponse) => { + switch (request.type) { + case BackgroundActionType.extract_data_request: + handleExtractData(request, sendResponse) + return true + case BackgroundActionType.connect_request: + handleConnect(request, sendResponse) + return true + case BackgroundActionType.disconnect_request: + handleDisconnect(request, sendResponse) + return true + default: + sendResponse({ error: 'Unknown action type' }) + break + } + }) +} + +async function handleConnect(request: BackgroundAction, sendResponse: (data?: any) => void) { + try { + const connection = await getConnection(request.data.origin) + + if (!connection) { + const defer = deferredPromise() + // Can be set to true/false if the user accepts/rejects the connection + defer.resolve(true) + await setConnection(request.data.origin) + + sendResponse(true) + } + } catch (error) { + sendResponse({ error: 'Failed to connect' }) + } +} + +async function handleDisconnect(request: BackgroundAction, sendResponse: (data?: any) => void) { + try { + const connection = await getConnection(request.data.origin) + + if (connection) { + await deleteConnection(request.data.origin) + sendResponse(true) + } else { + sendResponse({ error: 'No active connection found' }) + } + } catch (error) { + sendResponse({ error: 'Failed to disconnect' }) + } +} + +function handleExtractData(request: BackgroundAction, sendResponse: (data?: any) => void) { + if (!request.data.key) { + return sendResponse({ error: 'Key is required' }) + } + // Do something with the request.data.key + // For now, just return a response + // But you can use setters and getters to send public data to the content script + let responseData = 'extension public data' + if (request.data.key === 'secret') { + responseData = 'extension secret data' + } + sendResponse({ response: responseData }) +} diff --git a/extension/src/entries/Content/content.ts b/extension/src/entries/Content/content.ts new file mode 100644 index 0000000..a5b6d62 --- /dev/null +++ b/extension/src/entries/Content/content.ts @@ -0,0 +1,34 @@ +import { ContentScriptTypes, RPCClient } from './rpc' + +const client = new RPCClient() + +class Zkramp { + async extractData(key: string) { + const resp = await client.call(ContentScriptTypes.extract_data, { + key, + }) + + return resp + } + + async disconnect() { + const resp = await client.call(ContentScriptTypes.disconnect) + + return resp + } +} + +const connect = async () => { + const resp = await client.call(ContentScriptTypes.connect) + + if (resp) { + return new Zkramp() + } + + return null +} + +// @ts-ignore +window.zkramp = { + connect, +} diff --git a/extension/src/entries/Content/index.ts b/extension/src/entries/Content/index.ts new file mode 100644 index 0000000..8db7960 --- /dev/null +++ b/extension/src/entries/Content/index.ts @@ -0,0 +1,78 @@ +import { BackgroundActionType } from '../Background/rpc' +import { ContentScriptRequest, ContentScriptTypes, RPCServer } from './rpc' +;(async () => { + loadScript('content.js') + const server = new RPCServer() + + const sendMessageAsync = (message: any) => { + return new Promise((resolve, reject) => { + chrome.runtime.sendMessage(message, (response) => { + if (chrome.runtime.lastError) { + reject(chrome.runtime.lastError) + } else { + resolve(response) + } + }) + }) + } + + server.on(ContentScriptTypes.connect, async () => { + // @ts-ignore + const connected = await sendMessageAsync({ + type: BackgroundActionType.connect_request, + data: { + ...getOriginData(), + }, + }) + + if (!connected) throw new Error('user rejected.') + + return connected + }) + + server.on(ContentScriptTypes.disconnect, async () => { + // @ts-ignore + const disconnected = await sendMessageAsync({ + type: BackgroundActionType.disconnect_request, + data: { + ...getOriginData(), + }, + }) + + if (!disconnected) throw new Error('error.') + + return disconnected + }) + + server.on(ContentScriptTypes.extract_data, async (request: ContentScriptRequest<{ key: string }>) => { + const { key } = request.params || {} + + if (!key) throw new Error('params must include key of the request') + + // @ts-ignore + const response = await chrome.runtime.sendMessage({ + type: BackgroundActionType.extract_data_request, + data: { + ...getOriginData(), + key, + }, + }) + + return response + }) +})() + +function loadScript(filename: string) { + //@ts-ignore + const url = chrome.runtime.getURL(filename) + const script = document.createElement('script') + script.setAttribute('type', 'text/javascript') + script.setAttribute('src', url) + document.body.appendChild(script) +} + +function getOriginData() { + return { + origin: window.origin, + } +} diff --git a/extension/src/entries/Content/rpc.ts b/extension/src/entries/Content/rpc.ts new file mode 100644 index 0000000..4d80e4f --- /dev/null +++ b/extension/src/entries/Content/rpc.ts @@ -0,0 +1,102 @@ +import { deferredPromise, PromiseResolvers } from '../../utils/promise' + +export enum ContentScriptTypes { + connect = 'zkramp/cs/connect', + disconnect = 'zkramp/cs/disconnect', + extract_data = 'zkramp/cs/extract_data', +} + +export type ContentScriptRequest = { + zkramprpc: string +} & RPCRequest + +type ContentScriptResponse = { + zkramprpc: string +} & RPCResponse + +type RPCRequest = { + id: number + method: method + params?: params +} + +type RPCResponse = { + id: number + result?: never + error?: never +} + +export class RPCServer { + #handlers: Map) => Promise> = new Map() + + constructor() { + window.addEventListener('message', async (event: MessageEvent>) => { + const data = event.data + + if (data.zkramprpc !== '1.0') return + if (!data.method) return + + const handler = this.#handlers.get(data.method) + + if (handler) { + try { + const result = await handler(data) + window.postMessage({ + zkramprpc: '1.0', + id: data.id, + result, + }) + } catch (error) { + window.postMessage({ + zkramprpc: '1.0', + id: data.id, + error, + }) + } + } else { + throw new Error(`unknown method - ${data.method}`) + } + }) + } + + on(method: ContentScriptTypes, handler: (message: ContentScriptRequest) => Promise) { + this.#handlers.set(method, handler) + } +} + +export class RPCClient { + #requests: Map = new Map() + #id = 0 + + get id() { + return this.#id++ + } + + constructor() { + window.addEventListener('message', (event: MessageEvent) => { + const data = event.data + + if (data.zkramprpc !== '1.0') return + + const promise = this.#requests.get(data.id) + + if (promise) { + if (typeof data.result !== 'undefined') { + promise.resolve(data.result) + this.#requests.delete(data.id) + } else if (typeof data.error !== 'undefined') { + promise.reject(data.error) + this.#requests.delete(data.id) + } + } + }) + } + + async call(method: ContentScriptTypes, params?: any): Promise { + const request = { zkramprpc: '1.0', id: this.id, method, params } + const defer = deferredPromise() + this.#requests.set(request.id, defer) + window.postMessage(request, '*') + return defer.promise + } +} diff --git a/extension/src/manifest.json b/extension/src/manifest.json index 6f7385a..594dc30 100644 --- a/extension/src/manifest.json +++ b/extension/src/manifest.json @@ -15,13 +15,18 @@ "content_security_policy": { "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';" }, - "permissions": [ - "offscreen", - "storage", - "webRequest", - "activeTab", - "sidePanel", - "tabs", - "scripting" - ] + "content_scripts": [ + { + "matches": ["http://*/*", "https://*/*", ""], + "js": ["contentScript.js"], + "css": [] + } + ], + "web_accessible_resources": [ + { + "resources": ["content.js"], + "matches": ["http://*/*", "https://*/*", ""] + } + ], + "permissions": ["offscreen", "storage", "webRequest", "activeTab", "sidePanel", "tabs", "scripting"] } diff --git a/extension/src/utils/promise.ts b/extension/src/utils/promise.ts new file mode 100644 index 0000000..452b443 --- /dev/null +++ b/extension/src/utils/promise.ts @@ -0,0 +1,17 @@ +export const deferredPromise = (): { + promise: Promise + resolve: (data?: any) => void + reject: (reason?: any) => void +} => { + let resolve: (data?: any) => void, reject: (reason?: any) => void + + const promise = new Promise((_resolve, _reject) => { + resolve = _resolve + reject = _reject + }) + + // @ts-ignore + return { promise, resolve, reject } +} + +export type PromiseResolvers = ReturnType diff --git a/extension/webpack.config.js b/extension/webpack.config.js index 2bdfb5c..6789a8b 100644 --- a/extension/webpack.config.js +++ b/extension/webpack.config.js @@ -28,6 +28,8 @@ module.exports = { entry: { main: './src/entries/UI', background: './src/entries/Background', + content: './src/entries/Content/content.ts', + contentScript: './src/entries/Content/index.ts', }, performance: { hints: false, diff --git a/extension/yarn.lock b/extension/yarn.lock index 9b9d34c..7b44df4 100644 --- a/extension/yarn.lock +++ b/extension/yarn.lock @@ -3287,6 +3287,14 @@ dependencies: "@types/node" "*" +"@types/chrome@^0.0.270": + version "0.0.270" + resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.270.tgz#575f47107652ef75d4841ec8ffa018137c8f51e7" + integrity sha512-ADvkowV7YnJfycZZxL2brluZ6STGW+9oKG37B422UePf2PCXuFA/XdERI0T18wtuWPx0tmFeZqq6MOXVk1IC+Q== + dependencies: + "@types/filesystem" "*" + "@types/har-format" "*" + "@types/connect-history-api-fallback@^1.3.5": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" @@ -3348,6 +3356,18 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/filesystem@*": + version "0.0.36" + resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.36.tgz#7227c2d76bfed1b21819db310816c7821d303857" + integrity sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA== + dependencies: + "@types/filewriter" "*" + +"@types/filewriter@*": + version "0.0.33" + resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.33.tgz#d9d611db9d9cd99ae4e458de420eeb64ad604ea8" + integrity sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g== + "@types/graceful-fs@^4.1.2": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" @@ -3355,6 +3375,11 @@ dependencies: "@types/node" "*" +"@types/har-format@*": + version "1.2.15" + resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.15.tgz#f352493638c2f89d706438a19a9eb300b493b506" + integrity sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA== + "@types/hoist-non-react-statics@*": version "3.3.5" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494" @@ -3880,6 +3905,19 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" +abstract-level@^1.0.2, abstract-level@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.4.tgz#3ad8d684c51cc9cbc9cf9612a7100b716c414b57" + integrity sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg== + dependencies: + buffer "^6.0.3" + catering "^2.1.0" + is-buffer "^2.0.5" + level-supports "^4.0.0" + level-transcoder "^1.0.1" + module-error "^1.0.1" + queue-microtask "^1.2.3" + accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -4222,6 +4260,13 @@ ast-types-flow@^0.0.8: resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== +async-mutex@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.5.0.tgz#353c69a0b9e75250971a64ac203b0ebfddd75482" + integrity sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA== + dependencies: + tslib "^2.4.0" + async@^3.2.3: version "3.2.5" resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" @@ -4551,6 +4596,16 @@ brorand@^1.0.1, brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== +browser-level@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" + integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.1" + module-error "^1.0.2" + run-parallel-limit "^1.1.0" + browser-process-hrtime@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" @@ -4752,6 +4807,11 @@ case-sensitive-paths-webpack-plugin@^2.4.0: resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== +catering@^2.1.0, catering@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" + integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== + chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -4822,6 +4882,17 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== +classic-level@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.4.1.tgz#169ecf9f9c6200ad42a98c8576af449c1badbaee" + integrity sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.0" + module-error "^1.0.1" + napi-macros "^2.2.2" + node-gyp-build "^4.3.0" + clean-css@^5.2.2: version "5.3.3" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd" @@ -7456,6 +7527,11 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-buffer@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -8454,6 +8530,28 @@ launch-editor@^2.6.0: picocolors "^1.0.0" shell-quote "^1.8.1" +level-supports@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" + integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== + +level-transcoder@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" + integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== + dependencies: + buffer "^6.0.3" + module-error "^1.0.1" + +level@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/level/-/level-8.0.1.tgz#737161db1bc317193aca4e7b6f436e7e1df64379" + integrity sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ== + dependencies: + abstract-level "^1.0.4" + browser-level "^1.0.1" + classic-level "^1.2.0" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -8782,6 +8880,11 @@ mkdirp@~0.5.1: dependencies: minimist "^1.2.6" +module-error@^1.0.1, module-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" + integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -8819,6 +8922,11 @@ nanoid@^3.3.7: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +napi-macros@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" + integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== + natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -8857,6 +8965,11 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-gyp-build@^4.3.0: + version "4.8.1" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.1.tgz#976d3ad905e71b76086f4f0b0d3637fe79b6cda5" + integrity sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -10062,7 +10175,7 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== -queue-microtask@^1.2.2: +queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== @@ -10540,6 +10653,13 @@ rollup@^2.43.1: optionalDependencies: fsevents "~2.3.2" +run-parallel-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" + integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== + dependencies: + queue-microtask "^1.2.2" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -11535,6 +11655,11 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.4.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" From 3d01bbf6fe53ddac8631fff98d655346e5089cef Mon Sep 17 00:00:00 2001 From: 0xChqrles Date: Thu, 29 Aug 2024 18:07:51 +0200 Subject: [PATCH 4/9] Docs: Add @Ayoazeez26 as a contributor --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index e917307..553cb34 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -45,6 +45,15 @@ "contributions": [ "code" ] + }, + { + "login": "Ayoazeez26", + "name": "Abdulhakeem Abdulazeez Ayodeji", + "avatar_url": "https://avatars.githubusercontent.com/u/44169294?v=4", + "profile": "https://github.com/Ayoazeez26", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index c3f8f17..fabdf11 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ Thanks goes to these wonderful people. Follow the [contributors guide](https://g Uğur Eren
UÄŸur Eren

💻 Lindsay Morales
Lindsay Morales

💻 Charlotte
Charlotte

💻 + Abdulhakeem Abdulazeez Ayodeji
Abdulhakeem Abdulazeez Ayodeji

💻 From 55290843cd3d80163eb132c9e2aa8e2736753844 Mon Sep 17 00:00:00 2001 From: 0xChqrles Date: Thu, 29 Aug 2024 18:08:23 +0200 Subject: [PATCH 5/9] Docs: Add @luiz-lvj as a contributor --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 553cb34..2e93b09 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -54,6 +54,15 @@ "contributions": [ "code" ] + }, + { + "login": "luiz-lvj", + "name": "Luiz Vasconcelos Júnior", + "avatar_url": "https://avatars.githubusercontent.com/u/64055364?v=4", + "profile": "https://github.com/luiz-lvj", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index fabdf11..7a8372e 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ Thanks goes to these wonderful people. Follow the [contributors guide](https://g Lindsay Morales
Lindsay Morales

💻 Charlotte
Charlotte

💻 Abdulhakeem Abdulazeez Ayodeji
Abdulhakeem Abdulazeez Ayodeji

💻 + Luiz Vasconcelos Júnior
Luiz Vasconcelos Júnior

💻 From 3f6ac6ed0a94a1e360af109abe0f30b57477b0fb Mon Sep 17 00:00:00 2001 From: 0xChqrles Date: Thu, 29 Aug 2024 18:08:34 +0200 Subject: [PATCH 6/9] Docs: Add @lana-shanghai as a contributor --- .all-contributorsrc | 9 +++++++++ README.md | 1 + 2 files changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 2e93b09..b51c71c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -63,6 +63,15 @@ "contributions": [ "code" ] + }, + { + "login": "lana-shanghai", + "name": "lanaivina", + "avatar_url": "https://avatars.githubusercontent.com/u/31368580?v=4", + "profile": "https://github.com/lana-shanghai", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 7a8372e..96fb18e 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ Thanks goes to these wonderful people. Follow the [contributors guide](https://g Charlotte
Charlotte

💻 Abdulhakeem Abdulazeez Ayodeji
Abdulhakeem Abdulazeez Ayodeji

💻 Luiz Vasconcelos Júnior
Luiz Vasconcelos Júnior

💻 + lanaivina
lanaivina

💻 From da0571393b486cbbd98b90dbed7496c7922d1e24 Mon Sep 17 00:00:00 2001 From: 0xChqrles Date: Thu, 29 Aug 2024 18:08:46 +0200 Subject: [PATCH 7/9] Docs: Add @BryanBorck as a contributor --- .all-contributorsrc | 9 +++++++++ README.md | 3 +++ 2 files changed, 12 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index b51c71c..deb1397 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -72,6 +72,15 @@ "contributions": [ "code" ] + }, + { + "login": "BryanBorck", + "name": "Bryan", + "avatar_url": "https://avatars.githubusercontent.com/u/62529683?v=4", + "profile": "https://github.com/BryanBorck", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 96fb18e..bd635ca 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,9 @@ Thanks goes to these wonderful people. Follow the [contributors guide](https://g Luiz Vasconcelos Júnior
Luiz Vasconcelos Júnior

💻 lanaivina
lanaivina

💻 + + Bryan
Bryan

💻 + From c0cada63548efe2e4cc6deebafb967572952933a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20Eren?= Date: Sat, 31 Aug 2024 01:00:42 +0300 Subject: [PATCH 8/9] ci: fix contract tests (#48) --- .github/workflows/contracts.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml index 9b572d0..f061f70 100644 --- a/.github/workflows/contracts.yml +++ b/.github/workflows/contracts.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 - + - name: Set up Scarb uses: software-mansion/setup-scarb@v1 @@ -21,7 +21,7 @@ jobs: - name: Build cairo contracts run: scarb build working-directory: contracts - + tests: runs-on: ubuntu-latest steps: @@ -30,7 +30,10 @@ jobs: - name: Set up Scarb uses: software-mansion/setup-scarb@v1 - + + - name: Set up SNForge + uses: foundry-rs/setup-snfoundry@v3 + - name: Run cairo tests - run: scarb test - working-directory: contracts \ No newline at end of file + run: scarb test + working-directory: contracts From a2722f6b40a04e025ed8c77eaca6df1ebe0f02dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20Eren?= Date: Sat, 31 Aug 2024 01:06:08 +0300 Subject: [PATCH 9/9] feat: registration page (#46) * feat: Registration Page * feat: Register page * feat: new modal design & generate proof modal * fix: add box-shadow to modal --------- Co-authored-by: Chqrles --- client/src/App.tsx | 13 +- client/src/components/Button/index.tsx | 5 + .../components/GenerateProofModal/index.tsx | 33 +++++ client/src/components/Modal/Content.tsx | 76 +++++------ client/src/components/Modal/Overlay.tsx | 2 +- client/src/components/WalletSidebar/index.tsx | 2 +- client/src/pages/Register.tsx | 125 ++++++++++++++++++ client/src/pages/RegisterPage.tsx | 91 ------------- client/src/pages/Registration.tsx | 74 +++++++++++ client/src/theme/colors.ts | 1 + client/src/theme/components/icons.tsx | 36 +++++ client/src/theme/components/text.tsx | 6 +- 12 files changed, 323 insertions(+), 141 deletions(-) create mode 100644 client/src/components/GenerateProofModal/index.tsx create mode 100644 client/src/pages/Register.tsx delete mode 100644 client/src/pages/RegisterPage.tsx create mode 100644 client/src/pages/Registration.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index 8178d7e..ee3682b 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,7 +1,8 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom' import Layout from 'src/components/Layout' -import RegisterPage from './pages/RegisterPage' +import RegisterPage from './pages/Register' +import RegistrationPage from './pages/Registration' import SwapPage from './pages/Swap' import StarknetProvider from './providers/StarknetProvider' @@ -15,7 +16,15 @@ const router = createBrowserRouter([ ), }, { - path: '/register', + path: '/registration', + element: ( + + + + ), + }, + { + path: '/registration/register', element: ( diff --git a/client/src/components/Button/index.tsx b/client/src/components/Button/index.tsx index a6fcef3..2963f2d 100644 --- a/client/src/components/Button/index.tsx +++ b/client/src/components/Button/index.tsx @@ -1,12 +1,17 @@ import styled from 'styled-components' export const PrimaryButton = styled.button` + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; width: 100%; padding: 16px; background-color: ${({ theme }) => theme.accent1}; border: 0; border-radius: 12px; font-weight: 500; + text-decoration: none; cursor: pointer; &:disabled { diff --git a/client/src/components/GenerateProofModal/index.tsx b/client/src/components/GenerateProofModal/index.tsx new file mode 100644 index 0000000..c249c78 --- /dev/null +++ b/client/src/components/GenerateProofModal/index.tsx @@ -0,0 +1,33 @@ +import { ThemedText } from 'src/theme/components' +import { Logo } from 'src/theme/components/icons' + +import { Column } from '../Flex' +import Content from '../Modal/Content' +import Overlay from '../Modal/Overlay' +import Portal from '../Portal' + +function GenerateProofModalContent() { + return ( + + + + + + Snarkification of the elliptic curve... + + + This might take a while + + + ) +} + +export default function GenerateProofModal() { + return ( + + + + + + ) +} diff --git a/client/src/components/Modal/Content.tsx b/client/src/components/Modal/Content.tsx index 558c47b..e4a05c8 100644 --- a/client/src/components/Modal/Content.tsx +++ b/client/src/components/Modal/Content.tsx @@ -5,73 +5,57 @@ import { styled } from 'styled-components' import { Column, Row } from '../Flex' const StyledContent = styled.div` - border: 3px solid ${({ theme }) => theme.neutral1}; - padding: 80px 32px; - background: ${({ theme }) => theme.bg1}; - z-index: 1060; position: fixed; - width: 100%; - top: 0; - bottom: 0; + z-index: 1060; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); display: flex; flex-direction: column; justify-content: center; - - @media only screen and (min-width: ${({ theme }) => `${theme.breakpoint.xs}px`}) { - left: 50%; - top: 50%; - width: 386px; - transform: translate(-50%, -50%); - padding: 32px; - bottom: unset; - } + width: 100%; + max-width: 480px; + padding: 16px; + background: ${({ theme }) => theme.bg2}; + border: 1px solid ${({ theme }) => theme.border}; + border-radius: 20px; + box-shadow: 0px 4px 4px 4px rgba(0, 0, 0, 0.3), 0px 8px 12px 10px rgba(0, 0, 0, 0.15); ` const TitleContainer = styled(Row)` - position: absolute; width: 100%; - padding: 0 4px; - text-align: center; - top: 16px; - - & > div { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - width: 100%; - } +` - @media only screen and (min-width: ${({ theme }) => `${theme.breakpoint.xs}px`}) { - top: -32px; - text-align: left; - } +const Title = styled(ThemedText.HeadlineSmall)` + width: 100%; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; ` -const CloseContainer = styled.div` - position: absolute; - color: ${({ theme }) => theme.neutral1}; +const CloseContainer = styled.button` width: 28px; height: 28px; padding: 4px; + background: transparent; + color: ${({ theme }) => theme.neutral1}; + border: none; cursor: pointer; - border: 3px solid ${({ theme }) => theme.neutral1}; - top: -3px; - right: -3px; + transition: color 0.15s linear; & > svg { display: block; } &:hover { - background: ${({ theme }) => theme.neutral1}; - color: ${({ theme }) => theme.bg1}; + color: ${({ theme }) => theme.neutral2}; } ` interface ContentProps { children: React.ReactNode title: string - close: () => void + close?: () => void } export default function Content({ children, title, close }: ContentProps) { @@ -79,12 +63,14 @@ export default function Content({ children, title, close }: ContentProps) { - {title} - + {title} - - - + {close && ( + + + + )} + {children} diff --git a/client/src/components/Modal/Overlay.tsx b/client/src/components/Modal/Overlay.tsx index 4e6b4bf..8f5a2ea 100644 --- a/client/src/components/Modal/Overlay.tsx +++ b/client/src/components/Modal/Overlay.tsx @@ -15,7 +15,7 @@ const StyledOverlay = styled.div` ` interface OverlayProps { - onClick: () => void + onClick?: () => void } export default function Overlay({ onClick }: OverlayProps) { diff --git a/client/src/components/WalletSidebar/index.tsx b/client/src/components/WalletSidebar/index.tsx index 76ddf6e..342d7a7 100644 --- a/client/src/components/WalletSidebar/index.tsx +++ b/client/src/components/WalletSidebar/index.tsx @@ -88,7 +88,7 @@ export default function WalletSidebar({ onClose }: WalletSidebarProps) { - + Registration diff --git a/client/src/pages/Register.tsx b/client/src/pages/Register.tsx new file mode 100644 index 0000000..31c2391 --- /dev/null +++ b/client/src/pages/Register.tsx @@ -0,0 +1,125 @@ +import { useEffect, useState } from 'react' +import { PrimaryButton } from 'src/components/Button' +import { Column, Row } from 'src/components/Flex' +import GenerateProofModal from 'src/components/GenerateProofModal' +import { ThemedText } from 'src/theme/components' +import { LockClosed, LockOpen } from 'src/theme/components/icons' +import { styled, useTheme } from 'styled-components' + +const Layout = styled(Column)` + width: 100%; + margin: 0 auto; + justify-content: center; + flex: 1; +` + +const Content = styled(Column)` + max-width: 464px; + width: 100%; +` + +const Headline = styled(Row)` + width: 100%; + justify-content: space-between; + margin-bottom: ${({ theme }) => theme.grids.md}; +` + +const ContentCard = styled(Column)` + width: 100%; + border-radius: 12px; + overflow: hidden; +` + +const NoDataCard = styled(Column)` + width: 100%; + align-items: center; + justify-content: center; + padding: 32px 0; + background-color: ${({ theme }) => theme.bg3}; +` + +const RevtagCard = styled(Row)` + width: 100%; + justify-content: space-between; + padding: 24px 16px; + background-color: ${({ theme }) => theme.bg3}; +` + +const ProofCard = styled(Row)` + width: 100%; + justify-content: flex-end; + gap: 8px; + padding: 16px; + background-color: ${({ theme }) => theme.bg2}; +` + +export default function RegisterPage() { + const theme = useTheme() + const [revtag, setRevtag] = useState('') + const [generatingProof, setGeneratingProof] = useState(false) + const [proven, setProven] = useState(false) + + useEffect(() => { + if (generatingProof) { + setTimeout(() => { + setProven(true) + setGeneratingProof(false) + }, 5_000) + } + }, [generatingProof]) + + return ( + + + + Register + + + {!revtag && ( + <> + + + No data detected + + + + setRevtag('chqrlesjuzw')}> + Open sidebar + + + )} + + {revtag && ( + <> + + + Revtag: + {revtag} + + + + {proven ? ( + + ) : ( + + )} + + {proven ? ( + Proved + ) : ( + Unproved + )} + + + + !proven && setGeneratingProof(true)}> + {proven ? 'Complete registration' : 'Generate proof'} + + + )} + + + {generatingProof && } + + ) +} diff --git a/client/src/pages/RegisterPage.tsx b/client/src/pages/RegisterPage.tsx deleted file mode 100644 index 9b48191..0000000 --- a/client/src/pages/RegisterPage.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { useState } from 'react' -import { PrimaryButton } from 'src/components/Button' -import { Card } from 'src/components/Card' -import { Column, Row } from 'src/components/Flex' -import { ThemedText } from 'src/theme/components' -import { styled } from 'styled-components' - -const Layout = styled(Column)` - margin: 0 auto; - justify-content: center; - gap: 16px; - height: 100vh; -` -const RegistrationHeader = styled(Column)` - display: flex; - justify-content: space-between; - flex-direction: row; - width: 100%; -` - -const StatusCardGroup = styled(Row)` - width: 100%; - justify-content: space-between; -` - -const RegisterCard = styled(Card)` - width: 560px; -` - -export default function RegisterPage() { - const [displayRegister, setDisplayRegister] = useState(false) - - return ( - - {displayRegister ? ( - <> - - - setDisplayRegister(false)} style={{ cursor: 'pointer' }}> - Back - - New Registration -
-
- - - Use the ZKRamp browser assistant to generate proof a valid Revolut account. Submit the proof to complete - registration. - -
- - - Registration Proofs - - - - No Revolut account proofs found. Please follow instructions in the browser sidebar to generate proof of an - existing Revtag. - - - - Open Sidebar - - - - ) : ( - <> - Revolut Registration - - - You must register with a valid Revolut account to use ZKRamp. Your account details are hashed to conceal - your identity. - - - - - Status - - - Not Registered - - - setDisplayRegister(true)}> - + Register - - - - )} -
- ) -} diff --git a/client/src/pages/Registration.tsx b/client/src/pages/Registration.tsx new file mode 100644 index 0000000..deaddf9 --- /dev/null +++ b/client/src/pages/Registration.tsx @@ -0,0 +1,74 @@ +import { Link } from 'react-router-dom' +import { PrimaryButton } from 'src/components/Button' +import { Column, Row } from 'src/components/Flex' +import { ThemedText } from 'src/theme/components' +import { Empty, Plus } from 'src/theme/components/icons' +import { styled } from 'styled-components' + +const Layout = styled(Column)` + width: 100%; + margin: 0 auto; + justify-content: center; + flex: 1; +` + +const Content = styled(Column)` + max-width: 850px; + width: 100%; +` + +const Headline = styled(Row)` + width: 100%; + justify-content: space-between; + margin-bottom: ${({ theme }) => theme.grids.md}; +` + +const RegisterButton = styled(PrimaryButton)` + width: auto; + gap: 3px; + padding: 8px; + color: ${({ theme }) => theme.neutral1}; +` + +const ContentCard = styled(Column)` + width: 100%; + min-height: 220px; + padding: 20px 16px; + border: 1px solid ${({ theme }) => theme.border2}; + border-radius: 20px; +` + +const EmptyCard = styled(Column)` + flex: 1; + align-items: center; + justify-content: center; + gap: 8px; + color: ${({ theme }) => theme.neutral1}; +` + +export default function RegistrationPage() { + return ( + + + + Registration + + + + Register + + + + + + + + + Your registered accounts will appear here. + + + + + + ) +} diff --git a/client/src/theme/colors.ts b/client/src/theme/colors.ts index eeee35f..47d53c3 100644 --- a/client/src/theme/colors.ts +++ b/client/src/theme/colors.ts @@ -27,6 +27,7 @@ export const darkTheme = { surface: '#0D0D12', border: 'rgba(240, 247, 244, 0.1)', + border2: 'rgba(240, 247, 244, 0.5)', neutral1: colors.neutral1_dark, neutral2: colors.neutral2_dark, diff --git a/client/src/theme/components/icons.tsx b/client/src/theme/components/icons.tsx index 8ebcf9c..93f9ae0 100644 --- a/client/src/theme/components/icons.tsx +++ b/client/src/theme/components/icons.tsx @@ -113,3 +113,39 @@ export const Logout = (props: SVGProps) => ( /> ) + +export const Plus = (props: SVGProps) => ( + + + +) + +export const Empty = (props: SVGProps) => ( + + + +) + +export const LockOpen = (props: SVGProps) => ( + + + +) + +export const LockClosed = (props: SVGProps) => ( + + + +) diff --git a/client/src/theme/components/text.tsx b/client/src/theme/components/text.tsx index 5a5f752..8273ff7 100644 --- a/client/src/theme/components/text.tsx +++ b/client/src/theme/components/text.tsx @@ -36,7 +36,11 @@ export const ThemedText = { }, BodyPrimary(props: TextProps) { - return + return + }, + + BodySecondary(props: TextProps) { + return }, Title(props: TextProps) {