diff --git a/README.md b/README.md
index 48ddf39..e258bd6 100644
--- a/README.md
+++ b/README.md
@@ -78,8 +78,11 @@ Visit your app on: `http://localhost:3000`. You can interact with your smart con
For this hackathon I kept the scope small due to the time constraints. I build only the most essential and useful features, so that developers can start using Scaffold Move right away. However, there is much more that I want to add to this project after the hackathon. If you have any ideas or suggestions, please reach out and I will add it to this list.
-- Styling wallet connect button + add dropdown
-- Store network data in scaffold-config
+- Wallet button component
+ - Fix QR code
+ - Add network switch
+ - Styling of connect button
+- Store Aptos/Movement network data in scaffold-config
- Debug page
- Msg for no result on view methods
- Fix colors for dark mode
diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx
index 1dcdb5f..14dae44 100644
--- a/packages/nextjs/app/page.tsx
+++ b/packages/nextjs/app/page.tsx
@@ -2,12 +2,14 @@
import Link from "next/link";
import type { NextPage } from "next";
-import { useAccount } from "wagmi";
import { BugAntIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
-import { Address } from "~~/components/scaffold-eth";
+import { Address } from "~~/components/scaffold-move";
+import {
+ useWallet,
+} from "@aptos-labs/wallet-adapter-react";
const Home: NextPage = () => {
- const { address: connectedAddress } = useAccount();
+ const { account: connectedAccount } = useWallet();
return (
<>
@@ -19,7 +21,8 @@ const Home: NextPage = () => {
Get started by editing{" "}
diff --git a/packages/nextjs/components/Header.tsx b/packages/nextjs/components/Header.tsx
index 57430b7..1290aeb 100644
--- a/packages/nextjs/components/Header.tsx
+++ b/packages/nextjs/components/Header.tsx
@@ -8,6 +8,8 @@ import { WalletSelector } from "@aptos-labs/wallet-adapter-ant-design";
import { Bars3Icon, BugAntIcon } from "@heroicons/react/24/outline";
// import { FaucetButton } from "~~/components/scaffold-eth";
// import { useOutsideClick } from "~~/hooks/scaffold-eth";
+import {CustomConnectButton} from "~~/components/scaffold-move";
+
type HeaderMenuLink = {
label: string;
@@ -107,9 +109,7 @@ export const Header = () => {
);
diff --git a/packages/nextjs/components/scaffold-move/CustomConnectButton/AddressInfoDropdown.tsx b/packages/nextjs/components/scaffold-move/CustomConnectButton/AddressInfoDropdown.tsx
new file mode 100644
index 0000000..4f74b5d
--- /dev/null
+++ b/packages/nextjs/components/scaffold-move/CustomConnectButton/AddressInfoDropdown.tsx
@@ -0,0 +1,137 @@
+import { useRef, useState } from "react";
+import { NetworkOptions } from "./NetworkOptions";
+import CopyToClipboard from "react-copy-to-clipboard";
+import {
+ ArrowLeftOnRectangleIcon,
+ ArrowTopRightOnSquareIcon,
+ ArrowsRightLeftIcon,
+ CheckCircleIcon,
+ ChevronDownIcon,
+ DocumentDuplicateIcon,
+ QrCodeIcon,
+} from "@heroicons/react/24/outline";
+import { BlockieAvatar, isENS } from "~~/components/scaffold-eth";
+import { useOutsideClick } from "~~/hooks/scaffold-move";
+import { getTargetNetworks } from "~~/utils/scaffold-eth";
+import {
+ useWallet
+} from "@aptos-labs/wallet-adapter-react";
+
+const allowedNetworks = getTargetNetworks();
+
+type AddressInfoDropdownProps = {
+ address: string;
+ blockExplorerAddressLink: string | undefined;
+ displayName: string;
+ ensAvatar?: string;
+};
+
+export const AddressInfoDropdown = ({
+ address,
+ ensAvatar,
+ displayName,
+ blockExplorerAddressLink,
+}: AddressInfoDropdownProps) => {
+
+ const [addressCopied, setAddressCopied] = useState(false);
+
+ const [selectingNetwork, setSelectingNetwork] = useState(false);
+ const dropdownRef = useRef(null);
+ const closeDropdown = () => {
+ setSelectingNetwork(false);
+ dropdownRef.current?.removeAttribute("open");
+ };
+ useOutsideClick(dropdownRef, closeDropdown);
+
+
+ const { disconnect, wallet } = useWallet();
+ return (
+ <>
+
+
+
+
+ {isENS(displayName) ? displayName : address?.slice(0, 6) + "..." + address?.slice(-4)}
+
+
+
+
+
+
+ {addressCopied ? (
+
+
+ Copy address
+
+ ) : (
+ {
+ setAddressCopied(true);
+ setTimeout(() => {
+ setAddressCopied(false);
+ }, 800);
+ }}
+ >
+
+
+ Copy address
+
+
+ )}
+
+
+
+
+ View QR Code
+
+
+
+
+
+
+ View on Block Explorer
+
+
+
+ {allowedNetworks.length > 1 ? (
+
+ {
+ setSelectingNetwork(true);
+ }}
+ >
+ Switch Network
+
+
+ ) : null}
+
+ disconnect()}
+ >
+ Disconnect
+
+
+
+
+ >
+ );
+};
diff --git a/packages/nextjs/components/scaffold-move/CustomConnectButton/AddressQRCodeModal.tsx b/packages/nextjs/components/scaffold-move/CustomConnectButton/AddressQRCodeModal.tsx
new file mode 100644
index 0000000..d4eeb1f
--- /dev/null
+++ b/packages/nextjs/components/scaffold-move/CustomConnectButton/AddressQRCodeModal.tsx
@@ -0,0 +1,32 @@
+import { QRCodeSVG } from "qrcode.react";
+import { Address } from "~~/components/scaffold-move";
+
+type AddressQRCodeModalProps = {
+ address: string;
+ modalId: string;
+};
+
+export const AddressQRCodeModal = ({ address, modalId }: AddressQRCodeModalProps) => {
+ return (
+ <>
+
+ >
+ );
+};
diff --git a/packages/nextjs/components/scaffold-move/CustomConnectButton/NetworkOptions.tsx b/packages/nextjs/components/scaffold-move/CustomConnectButton/NetworkOptions.tsx
new file mode 100644
index 0000000..ee75438
--- /dev/null
+++ b/packages/nextjs/components/scaffold-move/CustomConnectButton/NetworkOptions.tsx
@@ -0,0 +1,43 @@
+import { useTheme } from "next-themes";
+import { useAccount, useSwitchChain } from "wagmi";
+import { ArrowsRightLeftIcon } from "@heroicons/react/24/solid";
+import { getTargetNetworks } from "~~/utils/scaffold-eth";
+
+const allowedNetworks = getTargetNetworks();
+
+type NetworkOptionsProps = {
+ hidden?: boolean;
+};
+
+export const NetworkOptions = ({ hidden = false }: NetworkOptionsProps) => {
+ const { switchChain } = useSwitchChain();
+ const { chain } = useAccount();
+ const { resolvedTheme } = useTheme();
+ const isDarkMode = resolvedTheme === "dark";
+
+ return (
+ <>
+ {allowedNetworks
+ .filter(allowedNetwork => allowedNetwork.id !== chain?.id)
+ .map(allowedNetwork => (
+
+ {
+ switchChain?.({ chainId: allowedNetwork.id });
+ }}
+ >
+
+
+ Switch to{" "}
+
+ {allowedNetwork.name}
+
+
+
+
+ ))}
+ >
+ );
+};
diff --git a/packages/nextjs/components/scaffold-move/CustomConnectButton/WrongNetworkDropdown.tsx b/packages/nextjs/components/scaffold-move/CustomConnectButton/WrongNetworkDropdown.tsx
new file mode 100644
index 0000000..f9f0fd8
--- /dev/null
+++ b/packages/nextjs/components/scaffold-move/CustomConnectButton/WrongNetworkDropdown.tsx
@@ -0,0 +1,32 @@
+import { NetworkOptions } from "./NetworkOptions";
+import { useDisconnect } from "wagmi";
+import { ArrowLeftOnRectangleIcon, ChevronDownIcon } from "@heroicons/react/24/outline";
+
+export const WrongNetworkDropdown = () => {
+ const { disconnect } = useDisconnect();
+
+ return (
+
+
+ Wrong network
+
+
+
+
+
+ disconnect()}
+ >
+
+ Disconnect
+
+
+
+
+ );
+};
diff --git a/packages/nextjs/components/scaffold-move/CustomConnectButton/index.tsx b/packages/nextjs/components/scaffold-move/CustomConnectButton/index.tsx
new file mode 100644
index 0000000..e3dcbc2
--- /dev/null
+++ b/packages/nextjs/components/scaffold-move/CustomConnectButton/index.tsx
@@ -0,0 +1,53 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { Balance } from "../Balance";
+import { AddressInfoDropdown } from "./AddressInfoDropdown";
+import { WrongNetworkDropdown } from "./WrongNetworkDropdown";
+import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork";
+import { getBlockExplorerAddressLink } from "~~/utils/scaffold-eth";
+import { WalletSelector } from "@aptos-labs/wallet-adapter-ant-design";
+
+
+import {
+ useWallet
+} from "@aptos-labs/wallet-adapter-react";
+
+export const CustomConnectButton = () => {
+ const { targetNetwork } = useTargetNetwork();
+ // const [account, setAccount] = useState(null);
+ const chain = {name: "devnet"}; // TODO: replace
+
+
+ const { account, connected} = useWallet();
+
+
+ const blockExplorerAddressLink = account ? getBlockExplorerAddressLink(targetNetwork, account?.address) : undefined;
+
+ return (
+ <>
+ {!connected ? (
+
+
+
+ )
+ // : chainId !== targetNetwork.id ? (
+ //
+ // )
+ : (
+ <>
+
+ {/* */}
+ {chain ? chain.name : "Loading..."}
+
+
+ >
+ )}
+ >
+ );
+};
diff --git a/packages/nextjs/components/scaffold-move/WalletContext.tsx b/packages/nextjs/components/scaffold-move/WalletContext.tsx
index b10c5ba..494e07d 100644
--- a/packages/nextjs/components/scaffold-move/WalletContext.tsx
+++ b/packages/nextjs/components/scaffold-move/WalletContext.tsx
@@ -2,8 +2,6 @@ import { ReactNode, createContext, useContext } from "react";
import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";
import { PetraWallet } from "petra-plugin-wallet-adapter";
-const WalletContext = createContext(null);
-
export const WalletProvider = ({ children }: { children: ReactNode }) => {
const wallets = [new PetraWallet()];
return (
@@ -12,7 +10,3 @@ export const WalletProvider = ({ children }: { children: ReactNode }) => {
);
};
-
-export const useAptosWallet = () => {
- return useContext(WalletContext);
-};
diff --git a/packages/nextjs/components/scaffold-move/index.tsx b/packages/nextjs/components/scaffold-move/index.tsx
index c64f173..8064f6b 100644
--- a/packages/nextjs/components/scaffold-move/index.tsx
+++ b/packages/nextjs/components/scaffold-move/index.tsx
@@ -1,2 +1,3 @@
export * from "./Address";
-export * from "./Balance";
\ No newline at end of file
+export * from "./Balance";
+export * from "./CustomConnectButton";
diff --git a/packages/nextjs/hooks/scaffold-move/index.ts b/packages/nextjs/hooks/scaffold-move/index.ts
index ae664be..b3ad99f 100644
--- a/packages/nextjs/hooks/scaffold-move/index.ts
+++ b/packages/nextjs/hooks/scaffold-move/index.ts
@@ -1,3 +1,4 @@
export * from "./useDeployedContractInfo";
export * from "./useGetAccountAPTBalance";
-export * from "./useGetAccountResources";
\ No newline at end of file
+export * from "./useGetAccountResources";
+export * from "./useOutsideClick";
\ No newline at end of file
diff --git a/packages/nextjs/hooks/scaffold-move/useOutsideClick.ts b/packages/nextjs/hooks/scaffold-move/useOutsideClick.ts
new file mode 100644
index 0000000..d7f2e0e
--- /dev/null
+++ b/packages/nextjs/hooks/scaffold-move/useOutsideClick.ts
@@ -0,0 +1,23 @@
+import React, { useEffect } from "react";
+
+/**
+ * Handles clicks outside of passed ref element
+ * @param ref - react ref of the element
+ * @param callback - callback function to call when clicked outside
+ */
+export const useOutsideClick = (ref: React.RefObject, callback: { (): void }) => {
+ useEffect(() => {
+ function handleOutsideClick(event: MouseEvent) {
+ if (!(event.target instanceof Element)) {
+ return;
+ }
+
+ if (ref.current && !ref.current.contains(event.target)) {
+ callback();
+ }
+ }
+
+ document.addEventListener("click", handleOutsideClick);
+ return () => document.removeEventListener("click", handleOutsideClick);
+ }, [ref, callback]);
+};
diff --git a/packages/nextjs/utils/scaffold-eth/networks.ts b/packages/nextjs/utils/scaffold-eth/networks.ts
index 6b8276f..0a658a2 100644
--- a/packages/nextjs/utils/scaffold-eth/networks.ts
+++ b/packages/nextjs/utils/scaffold-eth/networks.ts
@@ -113,16 +113,16 @@ export function getBlockExplorerTxLink(chainId: number, txnHash: string) {
* Defaults to Etherscan if no (wagmi) block explorer is configured for the network.
*/
export function getBlockExplorerAddressLink(network: chains.Chain, address: string) {
- const blockExplorerBaseURL = network.blockExplorers?.default?.url;
- if (network.id === chains.hardhat.id) {
- return `/blockexplorer/address/${address}`;
- }
+ // const blockExplorerBaseURL = network.blockExplorers?.default?.url;
+ // if (network.id === chains.hardhat.id) {
+ // return `/blockexplorer/address/${address}`;
+ // }
- if (!blockExplorerBaseURL) {
- return `https://etherscan.io/address/${address}`;
- }
+ // if (!blockExplorerBaseURL) {
+ return `https://explorer.devnet.m1.movementlabs.xyz/account/${address}?network=devnet`;
+ // }
- return `${blockExplorerBaseURL}/address/${address}`;
+ // return `${blockExplorerBaseURL}/address/${address}`;
}
/**