Compare commits

..

No commits in common. "8cad0db3b8be823fd165a5d380fb3cab6cb2c905" and "838f01baa524f8644d48c4a6214eb72dbdabb00a" have entirely different histories.

22 changed files with 192 additions and 844 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,10 @@
{ {
"author": "GHOST Team <someone@ghostchain.io>", "author": "Ghost Team <someone@ghostchain.io>",
"description": "Wallet for GHOST and CASPER blockchains light clients", "description": "Wallet for Ghost and Casper blockchains light clients",
"homepage_url": "https://git.ghostchain.io/ghostchain/ghost-extension-wallet", "homepage_url": "https://github.com/ghostchain/ghost-wallet",
"name": "GHOST Wallet", "name": "Ghost Wallet",
"short_name": "ghost-wallet", "short_name": "ghost-wallet",
"version": "0.0.1", "version": "0.0.0",
"manifest_version": 3, "manifest_version": 3,
"permissions": ["notifications", "storage", "tabs", "alarms"], "permissions": ["notifications", "storage", "tabs", "alarms"],
"background": { "background": {
@ -12,7 +12,7 @@
"type": "module" "type": "module"
}, },
"action": { "action": {
"default_title": "GHOST Wallet", "default_title": "Ghost Wallet",
"default_popup": "ui/assets/wallet-popup.html" "default_popup": "ui/assets/wallet-popup.html"
}, },
"options_ui": { "options_ui": {

View File

@ -1,10 +1,10 @@
{ {
"author": "GHOST Team <someone@ghostchain.io>", "author": "Ghost Team <someone@ghostchain.io>",
"description": "Wallet for GHOST and CASPER blockchains light clients", "description": "Wallet for Ghost and Casper blockchains light clients",
"homepage_url": "https://git.ghostchain.io/ghostchain/ghost-extension-wallet", "homepage_url": "https://github.com/ghostchain/ghost-wallet",
"name": "GHOST Wallet", "name": "Ghost Wallet",
"short_name": "ghost-wallet", "short_name": "ghost-wallet",
"version": "0.0.1", "version": "0.0.0",
"manifest_version": 3, "manifest_version": 3,
"permissions": ["notifications", "storage", "tabs", "alarms"], "permissions": ["notifications", "storage", "tabs", "alarms"],
"background": { "background": {
@ -12,7 +12,7 @@
"type": "module" "type": "module"
}, },
"action": { "action": {
"default_title": "GHOST Wallet", "default_title": "Ghost Wallet",
"default_popup": "ui/assets/wallet-popup.html" "default_popup": "ui/assets/wallet-popup.html"
}, },
"options_ui": { "options_ui": {
@ -37,7 +37,7 @@
}, },
"browser_specific_settings": { "browser_specific_settings": {
"gecko": { "gecko": {
"id": "{14b458b2-3221-4800-a36f-ae1ad1756ae2}" "id": "{9b4d20ed-b18a-4237-b5d0-ca71c2ce2060}"
} }
}, },
"web_accessible_resources": [ "web_accessible_resources": [

View File

@ -1,7 +1,7 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<title>GHOST Wallet Options</title> <title>Ghost Wallet Options</title>
<meta charset="utf-8" /> <meta charset="utf-8" />
</head> </head>
<body style="background-color: #f9f9f9"> <body style="background-color: #f9f9f9">

View File

@ -1,7 +1,7 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<title>GHOST Wallet</title> <title>Ghost Wallet</title>
<meta charset="utf-8" /> <meta charset="utf-8" />
</head> </head>
<body> <body>

View File

@ -3,11 +3,8 @@
NAME=$(grep "name" package.json | grep -oP '(?<=: ")[^"]+') NAME=$(grep "name" package.json | grep -oP '(?<=: ")[^"]+')
VERSION=$(grep "version" package.json | grep -oP '(?<=: ")[^"]+') VERSION=$(grep "version" package.json | grep -oP '(?<=: ")[^"]+')
BROWSERS=("chrome" "firefox") BROWSERS=("chrome" "firefox")
SCRIPT_DIR=$(dirname "$(realpath "$0")")
for BROWSER in "${BROWSERS[@]}"; do for BROWSER in "${BROWSERS[@]}"; do
FILENAME="$NAME-$BROWSER@v$VERSION.zip"
pnpm build:$BROWSER pnpm build:$BROWSER
python -m zipfile --create "$SCRIPT_DIR/releases/$FILENAME" "$SCRIPT_DIR/dist" python -m zipfile -c releases/$NAME-$BROWSER@v$VERSION /dist
python -m zipfile --test "$SCRIPT_DIR/releases/$FILENAME"
done done

View File

@ -1,6 +1,6 @@
{ {
"name": "ghost-wallet", "name": "ghost-wallet",
"version": "0.1.4", "version": "0.0.27",
"description": "Browser extension to manage ghost blockchain light clients.", "description": "Browser extension to manage ghost blockchain light clients.",
"main": "dist/src/index.js", "main": "dist/src/index.js",
"author": "Uncle f4ts0 <f4ts0@ghostchain.io>", "author": "Uncle f4ts0 <f4ts0@ghostchain.io>",
@ -146,7 +146,6 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"embla-carousel-react": "^8.5.1", "embla-carousel-react": "^8.5.1",
"input-otp": "^1.2.4", "input-otp": "^1.2.4",
"lodash": "^4.17.21",
"lucide-react": "^0.468.0", "lucide-react": "^0.468.0",
"next-themes": "^0.4.1", "next-themes": "^0.4.1",
"react": "^18.3.1", "react": "^18.3.1",

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
import { MdDeleteOutline } from "react-icons/md" import { MdDeleteOutline } from "react-icons/md"
import * as environment from "@/environment" import * as environment from "../environment"
import "./Bootnodes.css" import "./Bootnodes.css"
import { Title, Switch } from "." import { Title, Switch } from "."
import { helper } from "@substrate/light-client-extension-helpers/extension-page" import { helper } from "@substrate/light-client-extension-helpers/extension-page"
import { wellKnownGenesisHashByChainId, networks } from "@/constants" import { wellKnownGenesisHashByChainId } from "../constants"
import { import {
Select, Select,
@ -50,7 +50,7 @@ const saveToLocalStorage = async (
} }
export const Bootnodes = () => { export const Bootnodes = () => {
const [selectedChain, setSelectedChain] = useState<string>(networks[0].value) const [selectedChain, setSelectedChain] = useState<string>("casper_staging_testnet")
const [defaultBn, setDefaultBn] = useState<BootnodesType[]>([]) const [defaultBn, setDefaultBn] = useState<BootnodesType[]>([])
const [customBn, setCustomBn] = useState<BootnodesType[]>([]) const [customBn, setCustomBn] = useState<BootnodesType[]>([])
const [customBnInput, setCustomBnInput] = useState<string>("") const [customBnInput, setCustomBnInput] = useState<string>("")
@ -164,15 +164,9 @@ export const Bootnodes = () => {
</SelectTrigger> </SelectTrigger>
<SelectContent className="sm:w-[250px] w-[100%]"> <SelectContent className="sm:w-[250px] w-[100%]">
<SelectGroup> <SelectGroup>
{networks.map(network => ( <SelectItem data-testid="scheme-casper_staging_testnet" value="casper_staging_testnet">
<SelectItem Casper
key={network.chainId}
data-testid={`scheme-${network.value}`}
value={network.value}
>
{network.label}
</SelectItem> </SelectItem>
))}
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
</Select> </Select>

View File

@ -9,13 +9,13 @@ const buttonVariants = cva(
{ {
variants: { variants: {
variant: { variant: {
default: "bg-primary text-primary-foreground hover:bg-foreground hover:text-background active:text-primary-foreground", default: "bg-primary text-primary-foreground hover:bg-foreground hover:text-background",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-foreground hover:text-secondary active:text-secondary-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary-foreground hover:text-secondary",
ghost: "text-primary hover:bg-accent hover:text-background active:text-primary", ghost: "text-primary hover:bg-accent hover:text-background",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 active:text-destructive-foreground", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline active:text-primary", link: "text-primary underline-offset-4 hover:underline",
}, },
size: { size: {
default: "h-10 px-4 py-2", default: "h-10 px-4 py-2",

View File

@ -4,129 +4,7 @@ import { Check, ChevronDown, ChevronUp } from "lucide-react"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
type SafeSelectProps = React.ComponentProps<typeof SelectPrimitive.Root> & { const Select = SelectPrimitive.Root
debounceMs?: number;
leaveGraceMs?: number;
allowCloseAfterItemMs?: number
}
const Select = ({
children,
debounceMs = 200,
leaveGraceMs = 150,
allowCloseAfterItemMs = 250,
onOpenChange,
onValueChange,
open: controlledOpen,
...rest
}: SafeSelectProps) => {
const lastToggleRef = React.useRef<number>(0)
const isControlled = controlledOpen !== undefined
const [isOpen, setIsOpen] = React.useState<boolean>(false)
const pointerInside = React.useRef<boolean>(false)
const pointerLeaveTimer = React.useRef<number | null>(null)
const lastItemActivate = React.useRef<number>(0)
const handlePointerEnterContent = React.useCallback(() => {
pointerInside.current = true
if (pointerLeaveTimer.current) {
window.clearTimeout(pointerLeaveTimer.current)
pointerLeaveTimer.current = null
}
}, [])
const handlePointerLeaveContent = React.useCallback(() => {
if (pointerLeaveTimer.current) window.clearTimeout(pointerLeaveTimer.current)
pointerLeaveTimer.current = window.setTimeout(() => {
pointerInside.current = false
pointerLeaveTimer.current = null
}, leaveGraceMs) as unknown as number
}, [leaveGraceMs])
const handleItemActivate = React.useCallback(() => {
lastItemActivate.current = Date.now()
}, [])
const enhancedChildren = React.Children.map(children, (child) => {
if (!React.isValidElement(child)) return child
const type = (child.type as any)?.displayName || (child.type as any)?.name
if (
child.type === SelectPrimitive.Content ||
type === SelectPrimitive.Content?.displayName
) {
return React.cloneElement(child, {
onPointerEnter: (...args: any[]) => {
handlePointerEnterContent()
console.log("item enter")
const fn = (child.props as any).onPointerEnter
if (fn) fn(...args)
},
onPointerLeave: (...args: any[]) => {
handlePointerLeaveContent()
console.log("item leave")
const fn = (child.props as any).onPointerLeave
if (fn) fn(...args)
},
forceMount: true,
...child.props,
})
}
if (
child.type === SelectPrimitive.Item ||
type === SelectPrimitive.Item?.displayName
) {
return React.cloneElement(child, {
onPointerDown: (e: PointerEvent | React.PointerEvent) => {
handleItemActivate();
console.log("item active")
const fn = (child.props as any).onPointerDown;
if (fn) fn(e);
},
...child.props,
})
}
return child;
})
const setOpenInterval = React.useCallback(
(value: boolean) => {
const now = Date.now()
if (now - lastToggleRef.current < debounceMs) return
if (!value) {
if (now - lastItemActivate.current < allowCloseAfterItemMs) {
lastToggleRef.current = now
if (!isControlled) setIsOpen(false)
onOpenChange?.(false)
return
}
if (pointerInside.current) return
}
lastToggleRef.current = now
if (!isControlled) setIsOpen(value)
if (onOpenChange) onOpenChange(value)
},
[debounceMs, isControlled, onOpenChange, allowCloseAfterItemMs]
)
return (
<SelectPrimitive.Root
{...rest}
open={isControlled ? controlledOpen : isOpen}
onOpenChange={setOpenInterval}
onValueChange={(value) => {
onValueChange?.(value)
setIsOpen(false)
}}
>
{enhancedChildren}
</SelectPrimitive.Root>
)
}
const SelectGroup = SelectPrimitive.Group const SelectGroup = SelectPrimitive.Group

View File

@ -1,45 +1,17 @@
type Network = { export const wellKnownGenesisHashByChainId: Record<string, string> = {
chainId: string casper_staging_testnet: "0x07074eb5f47a6f4dd70430674e5174d5414bc055292b90392fb6f0a28c7524d1",
label: string
value: string
logo: string
prefix: number
decimals: number
} }
export const networks: Network[] = [ export const wellKnownChainIdByGenesisHash: Record<string, string> = {
{ "0x07074eb5f47a6f4dd70430674e5174d5414bc055292b90392fb6f0a28c7524d1": "casper_staging_testnet",
chainId: "0xa217f4ee58a944470e9633ca5bd6d28a428ed64cd9b6f3e413565f359f89af90",
value: "casper_staging_testnet",
label: "CASPER",
logo: "https://cryptologos.cc/logos/ghostchain-logo.svg",
prefix: 1996,
decimals: 18,
} }
]
export const wellKnownGenesisHashByChainId: Record<string, string> = export const wellKnownPrefixByGenesisHash: Record<string, number> = {
networks.reduce((wellKnownChainIds, { chainId, value }) => { "0x07074eb5f47a6f4dd70430674e5174d5414bc055292b90392fb6f0a28c7524d1": 1996,
wellKnownChainIds[value] = chainId }
return wellKnownChainIds
}, {})
export const wellKnownChainIdByGenesisHash: Record<string, string> = export const wellKnownDecimalsByGenesisHash: Record<string, number> = {
networks.reduce((wellKnownChainName, { chainId, value }) => { "0x07074eb5f47a6f4dd70430674e5174d5414bc055292b90392fb6f0a28c7524d1": 18,
wellKnownChainName[chainId] = value }
return wellKnownChainName
}, {})
export const wellKnownPrefixByGenesisHash: Record<string, number> =
networks.reduce((wellKnownPrefixes, { chainId, prefix }) => {
wellKnownPrefixes[chainId] = prefix
return wellKnownPrefixes
}, {})
export const wellKnownDecimalsByGenesisHash: Record<string, number> =
networks.reduce((wellKnownDecimals, { decimals, chainId }) => {
wellKnownDecimals[chainId] = decimals
return wellKnownDecimals
}, {})
export const CHANNEL_ID = "ghost-extension" export const CHANNEL_ID = "ghost-extension"

View File

@ -177,7 +177,7 @@ export const Options: FunctionComponent = () => {
> >
<FaGithub className="w-8 h-8" /> <FaGithub className="w-8 h-8" />
<div className="block float-left text-xs text-left"> <div className="block float-left text-xs text-left">
<div className="md:block hidden text-primary">GHOST Wallet Git</div> <div className="md:block hidden text-primary">Ghost Wallet Git</div>
<div className="text-accent">v {pckg.version}</div> <div className="text-accent">v {pckg.version}</div>
</div> </div>
</Link> </Link>

View File

@ -81,6 +81,7 @@ export const AccountDetails: React.FC = () => {
const wrappedRequestSecretKey = pendingWrapper(requestSecretKey) const wrappedRequestSecretKey = pendingWrapper(requestSecretKey)
const wrappedDeleteCryptoKey = pendingWrapper(deleteCryptoKey) const wrappedDeleteCryptoKey = pendingWrapper(deleteCryptoKey)
console.log(api)
return ( return (
<Layout2 innerClassName="bg-muted"> <Layout2 innerClassName="bg-muted">
<Header /> <Header />

View File

@ -26,7 +26,7 @@ import {
} from "@polkadot-labs/hdkd" } from "@polkadot-labs/hdkd"
import React from "react" import React from "react"
import { Header, BottomNavBar } from "../../components" import { Header, BottomNavBar } from "../../components"
import { networks } from "@/constants" import { networks } from "./networks"
type Scheme = "Sr25519" | "Ed25519" | "Ecdsa" type Scheme = "Sr25519" | "Ed25519" | "Ecdsa"
@ -98,7 +98,7 @@ export const Accounts = () => {
) )
const [selectedCryptoKeyName, setSelectedCryptoKeyName] = useState<string | undefined>() const [selectedCryptoKeyName, setSelectedCryptoKeyName] = useState<string | undefined>()
const [isPending, setIsPending] = useState<boolean>(false) const [isPending, setIsPending] = useState<boolean>()
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
useEffect(() => { useEffect(() => {
@ -170,7 +170,7 @@ export const Accounts = () => {
<Select <Select
disabled={!cryptoKeys || cryptoKeys.length === 0} disabled={!cryptoKeys || cryptoKeys.length === 0}
value={selectedCryptoKeyName} value={selectedCryptoKeyName}
onValueChange={(value) => setSelectedCryptoKeyName(value)} onValueChange={(v) => setSelectedCryptoKeyName(v)}
> >
<SelectTrigger className="w-[235px]" data-testid="accounts-select"> <SelectTrigger className="w-[235px]" data-testid="accounts-select">
<SelectValue placeholder="Select Crypto Key" /> <SelectValue placeholder="Select Crypto Key" />

View File

@ -5,7 +5,7 @@ import {
generateMnemonic, generateMnemonic,
mnemonicToEntropy, mnemonicToEntropy,
} from "@polkadot-labs/hdkd-helpers" } from "@polkadot-labs/hdkd-helpers"
import { networks } from "@/constants" import { networks } from "./networks"
import { SubmitHandler, useForm } from "react-hook-form" import { SubmitHandler, useForm } from "react-hook-form"
import { toHex } from "@polkadot-api/utils" import { toHex } from "@polkadot-api/utils"
import { useNavigate } from "react-router-dom" import { useNavigate } from "react-router-dom"

View File

@ -20,7 +20,7 @@ import {
ed25519CreateDerive, ed25519CreateDerive,
sr25519CreateDerive, sr25519CreateDerive,
} from "@polkadot-labs/hdkd" } from "@polkadot-labs/hdkd"
import { networks } from "@/constants" import { networks } from "./networks"
import { Layout2 } from "@/components/Layout2" import { Layout2 } from "@/components/Layout2"
import { BottomNavBar, Header } from "../../components" import { BottomNavBar, Header } from "../../components"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
@ -169,6 +169,7 @@ export function ImportAccounts() {
} }
const onSubmit: SubmitHandler<FormFields> = async (data) => { const onSubmit: SubmitHandler<FormFields> = async (data) => {
console.log("started")
let errorOccured = null let errorOccured = null
const keynameExists = await rpc.client.getCryptoKey(data.keyname) const keynameExists = await rpc.client.getCryptoKey(data.keyname)
@ -409,9 +410,10 @@ export function ImportAccounts() {
<FormItem className="mb-4"> <FormItem className="mb-4">
<FormControl> <FormControl>
<Select <Select
{...field}
disabled={isSubmitting} disabled={isSubmitting}
onValueChange={(scheme) => field.onChange(scheme)} onValueChange={(scheme) => field.onChange(scheme)}
name={field.name}
value={field.value}
> >
<SelectTrigger <SelectTrigger
className={`${field.value ? "text-primary" : "text-muted-foreground"} w-full`} className={`${field.value ? "text-primary" : "text-muted-foreground"} w-full`}

View File

@ -0,0 +1,17 @@
export type Network = {
chainId: string
label: string
value: string
logo: string
prefix: number
}
export const networks: Network[] = [
{
chainId: "0x07074eb5f47a6f4dd70430674e5174d5414bc055292b90392fb6f0a28c7524d1",
value: "casper_staging_testnet",
label: "Casper",
logo: "https://cryptologos.cc/logos/ghostchain-logo.svg",
prefix: 1996,
}
]

View File

@ -46,7 +46,7 @@ export const Welcome = () => {
<li className="flex items-center gap-3"> <li className="flex items-center gap-3">
<Signal className="w-8 h-8 text-primary" aria-hidden="true" /> <Signal className="w-8 h-8 text-primary" aria-hidden="true" />
<p className="ml-3 text-base"> <p className="ml-3 text-base">
Be connected to the GHOST and CASPER networks from your browser Be connected to the Ghost and Casper networks from your browser
</p> </p>
</li> </li>
<li className="flex items-center gap-3"> <li className="flex items-center gap-3">
@ -64,7 +64,7 @@ export const Welcome = () => {
<li className="flex items-center gap-3"> <li className="flex items-center gap-3">
<GlobeLock className="w-8 h-8 text-primary" aria-hidden="true" /> <GlobeLock className="w-8 h-8 text-primary" aria-hidden="true" />
<p className="ml-3 text-base"> <p className="ml-3 text-base">
Make your browser be part of the GHOST and CASPER networks Make your browser be part of the Ghost and Casper networks
</p> </p>
</li> </li>
</ul> </ul>

View File

@ -1,5 +1,3 @@
import { networks } from "@/constants"
export type StorageEntry = { type: "braveSetting" } export type StorageEntry = { type: "braveSetting" }
export type StorageEntryType<E extends StorageEntry> = export type StorageEntryType<E extends StorageEntry> =
@ -9,7 +7,7 @@ export async function getDefaultBootnodes(
chain: string, chain: string,
): Promise<string[] | undefined> { ): Promise<string[] | undefined> {
if ( if (
networks.map(network => network.value).includes(chain) ["casper_staging_testnet"].includes(chain)
) { ) {
const bootNodes = ( const bootNodes = (
await ( await (

View File

@ -16,7 +16,7 @@ import type { InPageRpcSpec } from "./types"
const PROVIDER_INFO = { const PROVIDER_INFO = {
uuid: crypto.randomUUID(), uuid: crypto.randomUUID(),
name: "GHOST Wallet Browser Extension", name: "Ghost Wallet Browser Extension",
icon: "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>", icon: "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>",
rdns: "io.ghostchain.GhostWalletExtension", rdns: "io.ghostchain.GhostWalletExtension",
} }