diff --git a/public/starknet_logo.png b/public/starknet_logo.png
new file mode 100644
index 0000000..49fac48
Binary files /dev/null and b/public/starknet_logo.png differ
diff --git a/src/app/globals.css b/src/app/globals.css
index 982f8dd..b6cc60a 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -2,6 +2,8 @@ html,
body {
max-width: 100vw;
overflow-x: hidden;
+ background-color: #000;
+ color: #fff;
}
body {
@@ -21,91 +23,146 @@ a {
text-decoration: none;
}
+.flex {
+ display: flex;
+}
+
+.align-items-center {
+ align-items: center;
+}
+
+.justify-content-center {
+ justify-content: center;
+}
+
.full {
width: 100%;
}
-/* Accordion */
+.full-height {
+ height: 100%;
+}
-.accordion-button {
- width: 100%;
+.column {
+ flex-direction: column;
+}
+
+/* Button -- START */
+button {
+ font-size: 18px;
+ font-weight: 500;
+ line-height: 24px;
+ text-align: left;
+ text-underline-position: from-font;
+ text-decoration-skip-ink: none;
+ border: none;
+ background-color: #262933;
+ color: #fff;
+ border-radius: 8px;
+ padding: 12px;
display: flex;
- justify-content: space-between;
align-items: center;
- background-color: transparent;
- border: none;
+ justify-content: space-between;
cursor: pointer;
- transition: background-color 0.2s;
- padding: 16px 0;
+ gap: 4px;
+ position: relative;
}
-.accordion-button-with-border {
- padding: 8px;
+button.sections-list-button {
+ background-color: #14161c;
+ color: #6f727c;
}
-.accordion-title {
- font-weight: bold;
- font-size: 1.5em;
+button:not(.selected, :disabled):hover {
+ background-color: #464c5e;
}
-.accordion-title-with-border {
- font-size: 1em;
+button.disabled {
+ opacity: 0.4;
+ cursor: default;
}
-.accordion-icon {
- width: 16px;
- height: 16px;
- transition: transform 0.2s;
+button.selected {
+ background-color: #aecbfc;
+ color: #090e12;
}
-.accordion-icon-open {
- transform: rotate(180deg);
+button.connector {
+ background-color: #464c5e;
+ height: 40px;
+ font-size: 14px;
+ line-height: 14px;
+ font-weight: 500;
+ gap: 8px;
+ justify-content: center;
}
-.accordion-content {
- overflow: hidden;
- transition: max-height 0.2s ease-out;
- max-height: 0;
+button.connector > div {
+ gap: 8px;
+ align-items: center;
}
-.accordion-content-open {
- max-height: 500px;
+.connectors-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+ gap: 16px;
}
-/* Button */
-button {
- border: 1px solid #c8c8c8;
- background-color: transparent;
- border-radius: 8px;
- padding: 8px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- cursor: pointer;
- gap: 4px;
- font-weight: bold;
-}
+/* Button -- END */
.chevron-right {
width: 16px;
height: 16px;
transition: transform 0.2s;
transform: rotate(-90deg);
+ color: #090e12;
+}
+
+.chevron-down {
+ width: 16px;
+ height: 16px;
+ transition: transform 0.2s;
+ color: #6f727c;
+}
+
+.chevron-up {
+ width: 16px;
+ height: 16px;
+ transition: transform 0.2s;
+ color: #6f727c;
+ transform: rotate(-180deg);
+}
+
+.chevron-left {
+ width: 16px;
+ height: 16px;
+ transition: transform 0.2s;
+ color: #6f727c;
+ transform: rotate(-270deg);
}
input,
textarea {
padding: 8px;
border-radius: 8px;
- border: 1px solid #c8c8c8;
+ border: 1px solid #464c5e;
+ background-color: #14161c;
+ color: #a2a2a2;
}
button[type="submit"] {
- background-color: #cefff3;
+ border: solid 1px #85b6ff;
+ color: #85b6ff;
+ text-align: center;
}
.demo-dapp-container {
- padding: 40px 0;
+ height: 100vh;
+ flex-direction: column;
+}
+
+.demo-dapp-container > div {
+ height: 100%;
}
/* Small screens (smartphones) - Portrait and Landscape */
@@ -123,3 +180,289 @@ button[type="submit"] {
padding: 16px;
}
}
+
+.full-flex {
+ flex: 1;
+ width: 100%;
+}
+
+/* Header */
+
+.header-container {
+ padding: 32px 116px 16px;
+}
+
+.header-logo-container {
+ gap: 12px;
+ align-items: center;
+ width: 100%;
+}
+
+.header-profile-container {
+ background-color: #14161c;
+ border-radius: 12px;
+ gap: 12px;
+ padding: 16px;
+}
+
+.header-balance {
+ align-items: center;
+ gap: 8px;
+}
+
+.header-address {
+ cursor: pointer;
+ align-items: center;
+ gap: 8px;
+}
+
+.header-title {
+ font-weight: 400;
+ font-size: 20px;
+ line-height: 24px;
+ letter-spacing: 1%;
+ margin-top: 2px;
+}
+
+.header-account-separator {
+ border-left: solid 1px #464c5e;
+ margin: -4px 0;
+}
+
+/* Header - END */
+
+/* Section */
+.section-layout-heading {
+ gap: 8px;
+ position: relative;
+ border-bottom: solid 1px #262933;
+ padding-bottom: 16px;
+}
+
+.section-layout-container {
+ flex-direction: column;
+ gap: 24px;
+ width: 100%;
+ background-color: #14161c;
+ padding: 24px;
+ border-radius: 12px;
+ height: fit-content;
+}
+
+.section-title {
+ font-size: 18px;
+ font-weight: 600;
+ line-height: 24px;
+ text-align: left;
+ text-underline-position: from-font;
+ text-decoration-skip-ink: none;
+}
+
+.connector-icon {
+ height: 17px;
+ width: 17px;
+}
+
+.connector-icon > svg {
+ height: 17px;
+ width: 17px;
+}
+
+.get-started-container {
+ gap: 120px;
+ padding: 56px 116px;
+}
+
+.get-started-container > div {
+ gap: 10px;
+}
+
+.get-started-title {
+ font-size: 48px;
+ font-weight: 600;
+ line-height: 58px;
+ text-align: left;
+ text-underline-position: from-font;
+ text-decoration-skip-ink: none;
+ color: "#FFF";
+}
+
+.get-started-title::before {
+ content: "Manage ";
+}
+
+.get-started-title::after {
+ content: " Starknet accounts";
+}
+
+.get-started-title {
+ color: #6f727c;
+}
+
+.get-started-title::before,
+.get-started-title::after {
+ color: #fff;
+}
+
+.get-started-subtitle {
+ color: #6f727c;
+ font-size: 16px;
+ font-weight: 500;
+ line-height: 24px;
+ text-align: left;
+ text-underline-position: from-font;
+ text-decoration-skip-ink: none;
+}
+
+/* Section */
+
+/* Status -- Start */
+.status-grid-container {
+ /* Create a grid with auto-fill columns, minimum 200px width */
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ /* Limit to maximum 4 columns using max-width */
+ max-width: 800px;
+ width: 100%;
+ gap: 80px;
+}
+
+.status-grid-item {
+ border-radius: 4px;
+ flex-direction: column;
+ gap: 8px;
+ overflow: hidden;
+}
+
+.status-grid-item-title {
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 14px;
+ text-align: left;
+ text-underline-position: from-font;
+ text-decoration-skip-ink: none;
+ color: #6f727c;
+}
+
+.status-grid-item-value {
+ font-size: 16px;
+ font-weight: 500;
+ line-height: 24px;
+ text-align: left;
+ text-underline-position: from-font;
+ text-decoration-skip-ink: none;
+ display: flex;
+ align-items: center;
+}
+
+.truncate {
+ display: inline-block;
+ max-width: 100%;
+ vertical-align: top;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+/* Ensure no more than 4 columns at any viewport width */
+@media (min-width: 1000px) {
+ .status-grid-container {
+ grid-template-columns: repeat(4, 1fr);
+ }
+}
+/* Status -- End */
+
+/* Sections list */
+.sections-container {
+ gap: 180px;
+ background-color: #090e12;
+ padding: 76px 116px;
+ flex: 1;
+ height: 100%;
+}
+
+.sections-list {
+ gap: 12px;
+ flex: 0.5;
+}
+
+/* Section list - End */
+
+/* Connection -- Start */
+
+.available-connector {
+ width: 100%;
+ padding: 12px;
+ background-color: #262933;
+ border-radius: 12px;
+ gap: 20px;
+}
+
+.starknet-react-connectors-title {
+ font-size: 16px;
+ font-weight: 500;
+ line-height: 24px;
+ text-align: left;
+ text-underline-position: from-font;
+ text-decoration-skip-ink: none;
+}
+/* Connection -- End */
+
+/* Sign message */
+.sign-message-form {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ padding: 4;
+ gap: 12px;
+ width: 100%;
+}
+/* Sign message -- End */
+
+.add-token-container {
+ color: 000;
+ border-width: 0px;
+ border-radius: 8px;
+ justify-content: flex-start;
+ width: 50%;
+}
+
+.network-container {
+ color: 000;
+ border-width: 0px;
+ border-radius: 8px;
+ justify-content: flex-start;
+ width: 100%;
+}
+
+.p-1 {
+ gap: 4px;
+}
+
+.p-2 {
+ gap: 8px;
+}
+
+.p-3 {
+ gap: 12px;
+}
+
+.p-4 {
+ gap: 16px;
+}
+
+.gap-1 {
+ gap: 4px;
+}
+
+.gap-2 {
+ gap: 8px;
+}
+
+.gap-3 {
+ gap: 12px;
+}
+
+.gap-4 {
+ gap: 16px;
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index fcef23f..599f1b5 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,6 +1,9 @@
import type { Metadata } from "next"
+import { Inter } from "next/font/google"
import "./globals.css"
+const inter = Inter({ subsets: ["latin"] })
+
export const metadata: Metadata = {
title: "Demo dapp starknet",
description:
@@ -14,7 +17,13 @@ export default function RootLayout({
}>) {
return (
-
{children}
+
+
+ {children}
+
+
)
}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index eeafec3..085525e 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,23 +1,16 @@
"use client"
import { StarknetDapp } from "@/components/StarknetDapp"
-import { Flex } from "@/components/ui/Flex"
import { connectors } from "@/connectors"
-import { CHAIN_ID } from "@/constants"
import { mainnet, sepolia } from "@starknet-react/chains"
import { publicProvider, StarknetConfig } from "@starknet-react/core"
-import { constants } from "starknet"
-
-/* TODO: update ui */
export default function Home() {
- const chains = [
- CHAIN_ID === constants.NetworkName.SN_MAIN ? mainnet : sepolia,
- ]
+ const chains = [mainnet, sepolia]
const providers = publicProvider()
return (
-
+
{/* eslint-disable @typescript-eslint/no-explicit-any */}
{/* eslint-enable @typescript-eslint/no-explicit-any */}
-
+
)
}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
new file mode 100644
index 0000000..add0ea3
--- /dev/null
+++ b/src/components/Header.tsx
@@ -0,0 +1,54 @@
+import { isMainnet, toHexChainid } from "@/helpers/chainId"
+import { formatTruncatedAddress } from "@/helpers/formatAddress"
+import { useAccount, useBalance } from "@starknet-react/core"
+import { AvatarIcon } from "./icons/AvatarIcon"
+import { LogoIcon } from "./icons/LogoIcon"
+import { WalletIcon } from "./icons/WalletIcon"
+
+const Header = () => {
+ const { address, isConnected, chainId } = useAccount()
+
+ const { data: balance } = useBalance({
+ address: address,
+ })
+
+ const hexChainId = toHexChainid(chainId)
+
+ return (
+
+
+
+
Demo dapp
+
+
+ {isConnected && (
+
+
+
+ {balance && balance?.formatted.length > 7
+ ? `${balance.formatted.slice(0, 7)} ETH`
+ : `${balance?.formatted} ETH`}
+
+
+
+ window.open(
+ isMainnet(hexChainId)
+ ? `https://voyager.online/contract/${address}`
+ : `https://sepolia.voyager.online/contract/${address}`,
+ "_blank",
+ )
+ }
+ >
+
+ {formatTruncatedAddress(address || "")}
+
+
+ )}
+
+
+ )
+}
+
+export { Header }
diff --git a/src/components/StarknetDapp.tsx b/src/components/StarknetDapp.tsx
index 0479d12..85a1e83 100644
--- a/src/components/StarknetDapp.tsx
+++ b/src/components/StarknetDapp.tsx
@@ -1,27 +1,81 @@
"use client"
import { SignMessage } from "@/components/sections/SignMessage"
import { Transactions } from "@/components/sections/Transactions/Transactions"
+import { useAccount } from "@starknet-react/core"
+import { useState } from "react"
import { Connect } from "./connect/Connect"
-import { Flex } from "./ui/Flex"
+import { Header } from "./Header"
import { AccountStatus } from "./sections/AccountStatus"
import { AddToken } from "./sections/ERC20/AddToken"
import { Network } from "./sections/Network/Network"
+import { SectionButton } from "./sections/SectionButton"
+import { Section } from "./sections/types"
-const StarknetDapp = () => (
-
-
-
-
-
-
-
-
-)
+const StarknetDapp = () => {
+ const [section, setSection] = useState(undefined)
+ const { isConnected } = useAccount()
+
+ return (
+
+
+
+
+
+
your
+
+ Starknet utilizes the power of STARK technology to ensure
+ computational integrity.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {section === "Connection" &&
}
+ {section === "Transactions" &&
}
+ {section === "Signing" &&
}
+ {section === "Network" &&
}
+ {section === "ERC20" &&
}
+
+
+
+ )
+}
export { StarknetDapp }
diff --git a/src/components/connect/Connect.tsx b/src/components/connect/Connect.tsx
index 64a3859..0aa683c 100644
--- a/src/components/connect/Connect.tsx
+++ b/src/components/connect/Connect.tsx
@@ -1,15 +1,16 @@
-import { useAccount, useConnect } from "@starknet-react/core"
+import { useAccount, useConnect, useDisconnect } from "@starknet-react/core"
+import Image from "next/image"
import { useEffect, useState } from "react"
-import { disconnect } from "starknetkit"
-import { Accordion } from "../ui/Accordion"
+import { SectionLayout } from "../sections/SectionLayout"
import { Button } from "../ui/Button"
-import { Flex } from "../ui/Flex"
import { ConnectorButton } from "./ConnectorButton"
import { ConnectStarknetkitModal } from "./ConnectStarknetkitModal"
+import { DisconnectIcon } from "../icons/DisconnectIcon"
const Connect = () => {
const { isConnected } = useAccount()
const { connectors } = useConnect()
+ const { disconnect } = useDisconnect({})
const [isClient, setIsClient] = useState(false)
useEffect(() => {
@@ -21,57 +22,59 @@ const Connect = () => {
}
return (
-
-
-
-
-
-
- {connectors.map((connector) => (
-
- ))}
-
- ),
- },
- ]}
- />
-
-
-
-
-
-
- ),
- },
- ]}
- />
-
+
+
+
+
+
+
+
+
+ Starknet-react connectors
+
+
+ {connectors.map((connector) => {
+ const icon =
+ typeof connector.icon === "string"
+ ? connector.icon
+ : connector.icon.dark
+ const isSvg = icon?.startsWith("
+
+
+
)
}
diff --git a/src/components/connect/ConnectStarknetkitModal.tsx b/src/components/connect/ConnectStarknetkitModal.tsx
index 30d572c..e3d4e98 100644
--- a/src/components/connect/ConnectStarknetkitModal.tsx
+++ b/src/components/connect/ConnectStarknetkitModal.tsx
@@ -18,6 +18,7 @@ const ConnectStarknetkitModal = () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
await connectAsync({ connector: connector as any })
}}
+ hideChevron
>
Starknetkit Modal
diff --git a/src/components/connect/ConnectorButton.tsx b/src/components/connect/ConnectorButton.tsx
index 911b4f3..9e88831 100644
--- a/src/components/connect/ConnectorButton.tsx
+++ b/src/components/connect/ConnectorButton.tsx
@@ -1,8 +1,11 @@
import { Connector, useConnect } from "@starknet-react/core"
-import { FC } from "react"
+import { FC, ReactNode } from "react"
import { Button } from "../ui/Button"
-const ConnectorButton: FC<{ connector: Connector }> = ({ connector }) => {
+const ConnectorButton: FC<{ connector: Connector; icon: ReactNode }> = ({
+ connector,
+ icon,
+}) => {
const { connectAsync } = useConnect()
if (!connector.available()) {
return null
@@ -10,13 +13,17 @@ const ConnectorButton: FC<{ connector: Connector }> = ({ connector }) => {
return (
)
}
diff --git a/src/components/icons/AvatarIcon.tsx b/src/components/icons/AvatarIcon.tsx
new file mode 100644
index 0000000..781d8e1
--- /dev/null
+++ b/src/components/icons/AvatarIcon.tsx
@@ -0,0 +1,36 @@
+const AvatarIcon = () => (
+
+)
+
+export { AvatarIcon }
diff --git a/src/components/icons/Chevron.tsx b/src/components/icons/Chevron.tsx
new file mode 100644
index 0000000..0c50a0b
--- /dev/null
+++ b/src/components/icons/Chevron.tsx
@@ -0,0 +1,65 @@
+const ChevronRight = () => (
+
+)
+
+const ChevronLeft = () => (
+
+)
+
+const ChevronUp = () => (
+
+)
+
+const ChevronDown = () => (
+
+)
+
+export { ChevronRight, ChevronLeft, ChevronUp, ChevronDown }
diff --git a/src/components/icons/CopyIcon.tsx b/src/components/icons/CopyIcon.tsx
new file mode 100644
index 0000000..b39e98f
--- /dev/null
+++ b/src/components/icons/CopyIcon.tsx
@@ -0,0 +1,32 @@
+import { FC } from "react"
+
+const CopyIcon: FC<{
+ copyValue?: string
+}> = ({ copyValue }) => (
+
+)
+
+export { CopyIcon }
diff --git a/src/components/icons/DisconnectIcon.tsx b/src/components/icons/DisconnectIcon.tsx
new file mode 100644
index 0000000..ad41cdf
--- /dev/null
+++ b/src/components/icons/DisconnectIcon.tsx
@@ -0,0 +1,32 @@
+const DisconnectIcon = () => (
+
+)
+
+export { DisconnectIcon }
diff --git a/src/components/icons/IconStatusIcon.tsx b/src/components/icons/IconStatusIcon.tsx
new file mode 100644
index 0000000..9a4997b
--- /dev/null
+++ b/src/components/icons/IconStatusIcon.tsx
@@ -0,0 +1,38 @@
+const IconStatusIcon = () => {
+ return (
+
+ )
+}
+
+export { IconStatusIcon }
diff --git a/src/components/icons/InfoIcon.tsx b/src/components/icons/InfoIcon.tsx
new file mode 100644
index 0000000..12709f7
--- /dev/null
+++ b/src/components/icons/InfoIcon.tsx
@@ -0,0 +1,19 @@
+import { FC, SVGProps } from "react"
+
+const InfoIcon: FC> = ({ ...props }) => (
+
+)
+
+export { InfoIcon }
diff --git a/src/components/icons/LogoIcon.tsx b/src/components/icons/LogoIcon.tsx
new file mode 100644
index 0000000..a6acf72
--- /dev/null
+++ b/src/components/icons/LogoIcon.tsx
@@ -0,0 +1,73 @@
+const LogoIcon = () => (
+
+)
+
+export { LogoIcon }
diff --git a/src/components/icons/WalletIcon.tsx b/src/components/icons/WalletIcon.tsx
new file mode 100644
index 0000000..13d80bc
--- /dev/null
+++ b/src/components/icons/WalletIcon.tsx
@@ -0,0 +1,33 @@
+const WalletIcon = () => (
+
+)
+
+export { WalletIcon }
diff --git a/src/components/sections/AccountStatus.tsx b/src/components/sections/AccountStatus.tsx
index 8b726a5..8a6110c 100644
--- a/src/components/sections/AccountStatus.tsx
+++ b/src/components/sections/AccountStatus.tsx
@@ -1,3 +1,4 @@
+import { toHexChainid } from "@/helpers/chainId"
import {
useAccount,
useBalance,
@@ -6,19 +7,24 @@ import {
useStarkProfile,
} from "@starknet-react/core"
import { FC } from "react"
-import { constants, num } from "starknet"
-import { Accordion } from "../ui/Accordion"
-import { Flex } from "../ui/Flex"
+import { constants } from "starknet"
+import { CopyIcon } from "../icons/CopyIcon"
-const Box: FC<{
+interface BoxProps {
title: string
value?: string
-}> = ({ title, value }) => (
-
-
- {title}: {value || "-----"}
+ copy?: boolean
+ truncate?: boolean
+}
+
+const Box: FC = ({ title, value, copy, truncate }) => (
+
+ {title}
+
+ {value || "-"}
+ {value && copy && }
-
+
)
const AccountStatus = () => {
@@ -37,72 +43,43 @@ const AccountStatus = () => {
address,
})
- const hexChainId =
- typeof chainId === "bigint" ? num.toHex(chainId ?? 0) : null
+ const hexChainId = toHexChainid(chainId)
return (
-
-
-
-
-
-
-
-
- {balance ? (
- 7
- ? `${balance.formatted.slice(0, 5)} ETH`
- : `${balance?.formatted} ETH`
- }
- />
- ) : (
-
- )}
-
-
-
-
-
- ),
- },
- ]}
- />
-
- ),
- },
- ]}
+ <>
+
+
+
+ 7
+ ? `${balance.formatted.slice(0, 7)} ETH`
+ : `${balance?.formatted} ETH`
+ : "-"
+ }
+ />
+
+
-
+ >
)
}
diff --git a/src/components/sections/ERC20/AddToken.tsx b/src/components/sections/ERC20/AddToken.tsx
index d91a2fc..d21bfaa 100644
--- a/src/components/sections/ERC20/AddToken.tsx
+++ b/src/components/sections/ERC20/AddToken.tsx
@@ -1,7 +1,6 @@
-import { Accordion } from "@/components/ui/Accordion"
import { Button } from "@/components/ui/Button"
-import { Flex } from "@/components/ui/Flex"
import { useAccount, useWalletRequest } from "@starknet-react/core"
+import { SectionLayout } from "../SectionLayout"
const AddToken = () => {
const { account, address } = useAccount()
@@ -25,31 +24,19 @@ const AddToken = () => {
}
return (
-
-
-
- ),
- },
- ]}
- />
+
+
+
+
+
)
}
diff --git a/src/components/sections/Network/AddNetwork.tsx b/src/components/sections/Network/AddNetwork.tsx
index 01f9769..cdfc62d 100644
--- a/src/components/sections/Network/AddNetwork.tsx
+++ b/src/components/sections/Network/AddNetwork.tsx
@@ -1,5 +1,4 @@
import { Button } from "@/components/ui/Button"
-import { Flex } from "@/components/ui/Flex"
import { ETHTokenAddress } from "@/constants"
import { useWalletRequest } from "@starknet-react/core"
import { shortString } from "starknet"
@@ -25,22 +24,17 @@ const AddNetwork = () => {
})
return (
-
+
-
+
)
}
diff --git a/src/components/sections/Network/ChangeNetwork.tsx b/src/components/sections/Network/ChangeNetwork.tsx
index 421678f..a8fd087 100644
--- a/src/components/sections/Network/ChangeNetwork.tsx
+++ b/src/components/sections/Network/ChangeNetwork.tsx
@@ -1,33 +1,32 @@
import { Button } from "@/components/ui/Button"
-import { Flex } from "@/components/ui/Flex"
-import { useWalletRequest } from "@starknet-react/core"
+import { isMainnet, toHexChainid } from "@/helpers/chainId"
+import { useAccount, useWalletRequest } from "@starknet-react/core"
import { constants } from "starknet"
const ChangeNetwork = () => {
+ const { chainId } = useAccount()
+
const walletRequest = useWalletRequest({
type: "wallet_switchStarknetChain",
params: {
- chainId: constants.StarknetChainId.SN_MAIN,
+ chainId: isMainnet(toHexChainid(chainId))
+ ? constants.StarknetChainId.SN_SEPOLIA
+ : constants.StarknetChainId.SN_MAIN,
},
})
return (
-
+
-
+
)
}
diff --git a/src/components/sections/Network/Network.tsx b/src/components/sections/Network/Network.tsx
index 9fa334c..b1cf06d 100644
--- a/src/components/sections/Network/Network.tsx
+++ b/src/components/sections/Network/Network.tsx
@@ -1,8 +1,7 @@
-import { Flex } from "@/components/ui/Flex"
+import { useAccount } from "@starknet-react/core"
+import { SectionLayout } from "../SectionLayout"
import { AddNetwork } from "./AddNetwork"
import { ChangeNetwork } from "./ChangeNetwork"
-import { Accordion } from "@/components/ui/Accordion"
-import { useAccount } from "@starknet-react/core"
const Network = () => {
const { account, address } = useAccount()
@@ -12,19 +11,12 @@ const Network = () => {
}
return (
-
-
-
-
- ),
- },
- ]}
- />
+
+
+
)
}
diff --git a/src/components/sections/SectionButton.tsx b/src/components/sections/SectionButton.tsx
new file mode 100644
index 0000000..5bdb90c
--- /dev/null
+++ b/src/components/sections/SectionButton.tsx
@@ -0,0 +1,34 @@
+import { FC } from "react"
+import { Button } from "../ui/Button"
+import { Section } from "./types"
+
+interface SectionButtonProps {
+ disabled?: boolean
+ section: Section
+ selected: boolean
+ setSection: (
+ value?: ((prevState?: Section | undefined) => Section) | undefined,
+ ) => void
+}
+
+const SectionButton: FC = ({
+ disabled,
+ section,
+ selected,
+ setSection,
+}) => {
+ return (
+
+ )
+}
+
+export { SectionButton }
diff --git a/src/components/sections/SectionLayout.tsx b/src/components/sections/SectionLayout.tsx
new file mode 100644
index 0000000..45f787a
--- /dev/null
+++ b/src/components/sections/SectionLayout.tsx
@@ -0,0 +1,27 @@
+import { FC, PropsWithChildren } from "react"
+import { IconStatusIcon } from "../icons/IconStatusIcon"
+import { InfoIcon } from "../icons/InfoIcon"
+
+interface SectionLayoutProps extends PropsWithChildren {
+ sectionTitle: string
+}
+
+const SectionLayout: FC = ({ children, sectionTitle }) => {
+ return (
+
+
+
+
{sectionTitle}
+
+
+
{children}
+
+ )
+}
+
+export { SectionLayout }
diff --git a/src/components/sections/SignMessage.tsx b/src/components/sections/SignMessage.tsx
index bad4e59..c3e3cf9 100644
--- a/src/components/sections/SignMessage.tsx
+++ b/src/components/sections/SignMessage.tsx
@@ -1,19 +1,16 @@
-import { Flex } from "@/components/ui/Flex"
+import { toHexChainid } from "@/helpers/chainId"
import { useAccount, useSignTypedData } from "@starknet-react/core"
import { useState } from "react"
-import { constants, num, stark } from "starknet"
+import { constants, stark } from "starknet"
import { Button } from "../ui/Button"
-import { Accordion } from "../ui/Accordion"
+import { SectionLayout } from "./SectionLayout"
const SignMessage = () => {
const { account, address, chainId } = useAccount()
const [shortText, setShortText] = useState("")
const [lastSig, setLastSig] = useState([])
- const hexChainId =
- typeof chainId === "bigint"
- ? (num.toHex(chainId ?? 0) as constants.StarknetChainId)
- : null
+ const hexChainId = toHexChainid(chainId)
const { signTypedDataAsync } = useSignTypedData({
params: {
@@ -54,141 +51,131 @@ const SignMessage = () => {
}
return (
- <>
-
+
+
+
+
+ {lastSig && lastSig.length > 0 && (
+ <>
+ {lastSig.length % 2 === 0 ? (
+ <>
+
+
+ >
+ ) : (
<>
-
-
+
)
}
diff --git a/src/components/sections/Transactions/SendERC20.tsx b/src/components/sections/Transactions/SendERC20.tsx
index b840aa4..a979535 100644
--- a/src/components/sections/Transactions/SendERC20.tsx
+++ b/src/components/sections/Transactions/SendERC20.tsx
@@ -1,42 +1,20 @@
-import { Flex } from "@/components/ui/Flex"
import { ETHTokenAddress } from "@/constants"
import { parseInputAmountToUint256 } from "@/helper/token"
import {
- Abi,
useAccount,
useContract,
useSendTransaction,
} from "@starknet-react/core"
import { useState } from "react"
import { Button } from "../../ui/Button"
-
-const abi = [
- {
- type: "function",
- name: "transfer",
- state_mutability: "external",
- inputs: [
- {
- name: "recipient",
- type: "core::starknet::contract_address::ContractAddress",
- },
- {
- name: "amount",
- type: "core::integer::u256",
- },
- ],
- outputs: [],
- },
-] as const satisfies Abi
+import { abi } from "./abi"
const SendERC20 = () => {
- const [transferTo, setTransferTo] = useState("")
- const [transferAmount, setTransferAmount] = useState("1")
+ const { account } = useAccount()
const [lastTxStatus, setLastTxStatus] = useState("idle")
const [lastTxError, setLastTxError] = useState("")
- const { account } = useAccount()
const { contract } = useContract({
abi,
address: ETHTokenAddress,
@@ -48,7 +26,7 @@ const SendERC20 = () => {
? [
contract.populate("transfer", [
account?.address,
- parseInputAmountToUint256(transferAmount || "0"),
+ parseInputAmountToUint256("0.000000001"),
]),
]
: undefined,
@@ -71,48 +49,19 @@ const SendERC20 = () => {
}
return (
-
-
-
+
+
+ {lastTxError ? (
+ Error: {lastTxError}
+ ) : null}
+
)
}
diff --git a/src/components/sections/Transactions/SendMulticall.tsx b/src/components/sections/Transactions/SendMulticall.tsx
index 8a5b3ee..3fb8042 100644
--- a/src/components/sections/Transactions/SendMulticall.tsx
+++ b/src/components/sections/Transactions/SendMulticall.tsx
@@ -1,34 +1,14 @@
// TokenOperations.tsx
-import { Flex } from "@/components/ui/Flex"
import { ETHTokenAddress } from "@/constants"
import { parseInputAmountToUint256 } from "@/helper/token"
import {
- Abi,
useAccount,
useContract,
useSendTransaction,
} from "@starknet-react/core"
import { useState } from "react"
import { Button } from "../../ui/Button"
-
-const abi = [
- {
- type: "function",
- name: "transfer",
- state_mutability: "external",
- inputs: [
- {
- name: "recipient",
- type: "core::starknet::contract_address::ContractAddress",
- },
- {
- name: "amount",
- type: "core::integer::u256",
- },
- ],
- outputs: [],
- },
-] as const satisfies Abi
+import { abi } from "./abi"
const SendMulticall = () => {
const { account } = useAccount()
@@ -74,11 +54,12 @@ const SendMulticall = () => {
}
return (
-
+
)
}
diff --git a/src/components/sections/Transactions/Transactions.tsx b/src/components/sections/Transactions/Transactions.tsx
index a038a54..81e21e8 100644
--- a/src/components/sections/Transactions/Transactions.tsx
+++ b/src/components/sections/Transactions/Transactions.tsx
@@ -1,13 +1,9 @@
-import { Flex } from "@/components/ui/Flex"
import { useAccount } from "@starknet-react/core"
-import { useState } from "react"
-import { Accordion } from "../../ui/Accordion"
-import { Button } from "../../ui/Button"
+import { SectionLayout } from "../SectionLayout"
import { SendERC20 } from "../Transactions/SendERC20"
import { SendMulticall } from "../Transactions/SendMulticall"
const Transactions = () => {
- const [showErc20, setShowErc20] = useState(false)
const { account, address } = useAccount()
if (!account || !address) {
@@ -15,31 +11,12 @@ const Transactions = () => {
}
return (
- <>
-
-
-
- {showErc20 && }
-
-
- >
- ),
- },
- ]}
- />
- >
+
+
+
+
+
+
)
}
diff --git a/src/components/sections/Transactions/abi.ts b/src/components/sections/Transactions/abi.ts
new file mode 100644
index 0000000..928d0de
--- /dev/null
+++ b/src/components/sections/Transactions/abi.ts
@@ -0,0 +1,22 @@
+import { Abi } from "@starknet-react/core"
+
+const abi = [
+ {
+ type: "function",
+ name: "transfer",
+ state_mutability: "external",
+ inputs: [
+ {
+ name: "recipient",
+ type: "core::starknet::contract_address::ContractAddress",
+ },
+ {
+ name: "amount",
+ type: "core::integer::u256",
+ },
+ ],
+ outputs: [],
+ },
+] as const satisfies Abi
+
+export { abi }
diff --git a/src/components/sections/types.ts b/src/components/sections/types.ts
new file mode 100644
index 0000000..3c86beb
--- /dev/null
+++ b/src/components/sections/types.ts
@@ -0,0 +1,6 @@
+export type Section =
+ | "Connection"
+ | "Transactions"
+ | "Signing"
+ | "Network"
+ | "ERC20"
diff --git a/src/components/ui/Accordion.tsx b/src/components/ui/Accordion.tsx
deleted file mode 100644
index b7c8054..0000000
--- a/src/components/ui/Accordion.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React, { FC, useEffect, useState } from "react"
-import { AccordionItem } from "./AccordionItem"
-
-interface AccordionProps {
- withBorder?: boolean
- isDefaultOpen?: boolean
- items?: {
- title: string
- content: React.ReactNode
- }[]
-}
-
-const styles = {
- container: {
- border: "1px solid #C8C8C8",
- borderRadius: "8px",
- },
-}
-
-const Accordion: FC = ({
- items = [],
- withBorder,
- isDefaultOpen,
-}) => {
- const [openIndices, setOpenIndices] = useState([])
-
- const accordionItems = items.length > 0 ? items : []
-
- const handleClick = (index: number) => {
- setOpenIndices((prevIndices) => {
- if (prevIndices.includes(index)) {
- // If already open, close it
- return prevIndices.filter((i) => i !== index)
- } else {
- // If closed, add it to open indices
- return [...prevIndices, index]
- }
- })
- }
-
- useEffect(() => {
- if (isDefaultOpen) {
- setOpenIndices([0])
- }
- }, [])
-
- return (
-
- {accordionItems.map((item, index) => (
-
handleClick(index)}
- withBorder={withBorder}
- >
- {item.content || "No content provided"}
-
- ))}
-
- )
-}
-
-export { Accordion }
diff --git a/src/components/ui/AccordionItem.tsx b/src/components/ui/AccordionItem.tsx
deleted file mode 100644
index fddea47..0000000
--- a/src/components/ui/AccordionItem.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React, { FC } from "react"
-
-interface AccordionItemProps {
- title: string
- children: React.ReactNode
- isOpen: boolean
- onClick: () => void
- withBorder?: boolean
-}
-
-const AccordionItem: FC = ({
- title,
- children,
- isOpen,
- onClick,
- withBorder,
-}) => {
- return (
-
-
-
-
- )
-}
-
-export { AccordionItem }
diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx
index 965f47f..167b574 100644
--- a/src/components/ui/Button.tsx
+++ b/src/components/ui/Button.tsx
@@ -1,7 +1,11 @@
-import { ButtonHTMLAttributes, FC } from "react"
+import { ButtonHTMLAttributes, FC, ReactNode } from "react"
+import { ChevronDown, ChevronRight } from "../icons/Chevron"
interface ButtonProps extends ButtonHTMLAttributes {
hideChevron?: boolean
+ selected?: boolean
+ leftIcon?: ReactNode
+ rightIcon?: ReactNode
}
const Button: FC = ({
@@ -9,6 +13,9 @@ const Button: FC = ({
children,
style,
hideChevron,
+ selected,
+ leftIcon,
+ rightIcon,
...props
}) => (
)
diff --git a/src/components/ui/Flex.tsx b/src/components/ui/Flex.tsx
deleted file mode 100644
index 981169e..0000000
--- a/src/components/ui/Flex.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { CSSProperties, FC, ReactNode } from "react"
-
-interface FlexProps extends CSSProperties {
- className?: string
- children: ReactNode
-}
-
-const Flex: FC = ({ children, className, ...props }) => {
- return (
-
- {children}
-
- )
-}
-
-export { Flex }
diff --git a/src/helpers/chainId.ts b/src/helpers/chainId.ts
new file mode 100644
index 0000000..c9251db
--- /dev/null
+++ b/src/helpers/chainId.ts
@@ -0,0 +1,10 @@
+import { constants, num } from "starknet"
+
+const toHexChainid = (chainId?: bigint): string | null =>
+ typeof chainId === "bigint" ? num.toHex(chainId ?? 0) : null
+const isMainnet = (hexChainId: string | null) =>
+ hexChainId === constants.StarknetChainId.SN_MAIN
+const isTestnet = (hexChainId: string | null) =>
+ hexChainId === constants.StarknetChainId.SN_SEPOLIA
+
+export { toHexChainid, isMainnet, isTestnet }
diff --git a/src/helpers/formatAddress.ts b/src/helpers/formatAddress.ts
new file mode 100644
index 0000000..3588788
--- /dev/null
+++ b/src/helpers/formatAddress.ts
@@ -0,0 +1,13 @@
+import { Address } from "@starknet-react/core"
+import { getChecksumAddress } from "starknet"
+
+export const normalizeAddress = (address: string) =>
+ getChecksumAddress(address) as Address
+
+export const formatTruncatedAddress = (address: string) => {
+ const normalized = normalizeAddress(address)
+ const hex = normalized.slice(0, 2)
+ const start = normalized.slice(2, 6)
+ const end = normalized.slice(-4)
+ return `${hex}${start}…${end}`
+}