register_ui: start refactor...

This commit is contained in:
bitful-pannul 2024-06-24 18:56:34 -07:00
parent fe832b181d
commit afc15897e3
36 changed files with 11702 additions and 33753 deletions

File diff suppressed because it is too large Load Diff

View File

@ -8,26 +8,15 @@
"@ensdomains/eth-ens-namehash": "^2.0.15",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@ethersproject/hash": "^5.7.0",
"@typechain/ethers-v5": "^11.1.1",
"@types/node": "^16.18.50",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@unocss/vite": "^0.59.4",
"@vitejs/plugin-react": "^4.2.1",
"@web3-react/coinbase-wallet": "^8.2.3",
"@web3-react/core": "^8.2.2",
"@web3-react/gnosis-safe": "^8.2.4",
"@web3-react/injected-connector": "^6.0.7",
"@web3-react/metamask": "^8.2.3",
"@web3-react/network": "^8.2.3",
"@web3-react/types": "^8.2.2",
"@web3-react/walletconnect": "^8.2.3",
"@web3-react/walletconnect-connector": "^6.2.13",
"@web3-react/walletconnect-v2": "^8.5.1",
"@rainbow-me/rainbowkit": "^2.1.2",
"@szhsin/react-menu": "^4.1.0",
"@tanstack/react-query": "^5.45.1",
"buffer": "^6.0.3",
"js-sha3": "^0.9.3",
"classnames": "^2.5.1",
"eslint-config-react-app": "^7.0.1",
"ethers": "^5.7.2",
"idna-uts46-hx": "^6.0.4",
"is-valid-domain": "^0.1.6",
"jazzicon": "^1.5.0",
@ -42,10 +31,13 @@
"typescript": "^5.3.3",
"unocss": "^0.59.4",
"vite": "^5.2.10",
"vite-plugin-svgr": "^4.2.0"
"viem": "^2.15.1",
"vite-plugin-svgr": "^4.2.0",
"wagmi": "^2.10.3"
},
"scripts": {
"start": "vite",
"dev": "vite --port 3000",
"build": "npm run tc && tsc && vite build && rm -rf build && mv dist build",
"build:copy": "npm run build",
"serve": "vite preview",
@ -75,7 +67,8 @@
},
"devDependencies": {
"@types/react-modal": "^3.16.2",
"inline-source-cli": "^2.0.0"
"inline-source-cli": "^2.0.0",
"@types/react-dom": "^18.2.17"
},
"type": "module"
}
}

View File

@ -1,31 +1,8 @@
import { useState, useEffect, useMemo } from "react";
import { useState, useEffect } from "react";
import { Navigate, BrowserRouter as Router, Route, Routes, useParams } from 'react-router-dom';
import { hooks } from "./connectors/metamask";
import {
KNS_REGISTRY_ADDRESSES,
DOT_OS_ADDRESSES,
ENS_REGISTRY_ADDRESSES,
NAMEWRAPPER_ADDRESSES,
KNS_ENS_ENTRY_ADDRESSES,
KNS_ENS_EXIT_ADDRESSES,
} from "./constants/addresses";
import { ChainId } from "./constants/chainId";
import {
KNSRegistryResolver,
KNSRegistryResolver__factory,
DotOsRegistrar,
DotOsRegistrar__factory,
KNSEnsEntry,
KNSEnsEntry__factory,
KNSEnsExit,
KNSEnsExit__factory,
NameWrapper,
NameWrapper__factory,
ENSRegistry,
ENSRegistry__factory
} from "./abis/types";
import { ethers } from "ethers";
import ConnectWallet from "./components/ConnectWallet";
import { ConnectButton } from '@rainbow-me/rainbowkit';
import RegisterEthName from "./pages/RegisterEthName";
import RegisterKnsName from "./pages/RegisterKnsName";
import ClaimOsInvite from "./pages/ClaimKnsInvite";
@ -38,12 +15,8 @@ import ImportKeyfile from "./pages/ImportKeyfile";
import { UnencryptedIdentity } from "./lib/types";
import { getFetchUrl } from "./utils/fetch";
const {
useProvider,
} = hooks;
function App() {
const provider = useProvider();
const params = useParams()
const [pw, setPw] = useState<string>('');
@ -67,49 +40,6 @@ function App() {
const openConnect = () => setConnectOpen(true)
const closeConnect = () => setConnectOpen(false)
const rpcUrl = useMemo(() => provider?.network?.chainId === ChainId.SEPOLIA ? import.meta.env.REACT_APP_SEPOLIA_RPC_URL : import.meta.env.REACT_APP_OPTIMISM_RPC_URL, [provider])
const [dotOs, setDotOs] = useState<DotOsRegistrar>();
const [kns, setKns] = useState<KNSRegistryResolver>();
const [knsEnsEntry, setKnsEnsEntry] = useState<KNSEnsEntry>();
const [knsEnsExit, setKnsEnsExit] = useState<KNSEnsExit>();
const [nameWrapper, setNameWrapper] = useState<NameWrapper>();
const [ensRegistry, setEnsRegistry] = useState<ENSRegistry>();
useEffect(() => {
if (rpcUrl) {
setDotOs(DotOsRegistrar__factory.connect(
provider?.network?.chainId === ChainId.SEPOLIA ? DOT_OS_ADDRESSES[ChainId.SEPOLIA] : DOT_OS_ADDRESSES[ChainId.OPTIMISM],
new ethers.providers.JsonRpcProvider(rpcUrl)
))
setKns(KNSRegistryResolver__factory.connect(
provider?.network?.chainId === ChainId.SEPOLIA ? KNS_REGISTRY_ADDRESSES[ChainId.SEPOLIA] : KNS_REGISTRY_ADDRESSES[ChainId.OPTIMISM],
new ethers.providers.JsonRpcProvider(rpcUrl)
))
setKnsEnsEntry(KNSEnsEntry__factory.connect(
provider?.network?.chainId === ChainId.SEPOLIA ? KNS_ENS_ENTRY_ADDRESSES[ChainId.SEPOLIA] : KNS_ENS_ENTRY_ADDRESSES[ChainId.MAINNET],
new ethers.providers.JsonRpcProvider(provider?.network?.chainId === ChainId.SEPOLIA ? import.meta.env.REACT_APP_SEPOLIA_RPC_URL : import.meta.env.REACT_APP_MAINNET_RPC_URL)
))
setKnsEnsExit(KNSEnsExit__factory.connect(
provider?.network?.chainId === ChainId.SEPOLIA ? KNS_ENS_EXIT_ADDRESSES[ChainId.SEPOLIA] : KNS_ENS_EXIT_ADDRESSES[ChainId.OPTIMISM],
new ethers.providers.JsonRpcProvider(rpcUrl)
))
setNameWrapper(NameWrapper__factory.connect(
provider?.network?.chainId === ChainId.SEPOLIA ? NAMEWRAPPER_ADDRESSES[ChainId.SEPOLIA] : NAMEWRAPPER_ADDRESSES[ChainId.MAINNET],
new ethers.providers.JsonRpcProvider(rpcUrl)
))
setEnsRegistry(ENSRegistry__factory.connect(
provider?.network?.chainId === ChainId.SEPOLIA ? ENS_REGISTRY_ADDRESSES[ChainId.SEPOLIA] : ENS_REGISTRY_ADDRESSES[ChainId.MAINNET],
new ethers.providers.JsonRpcProvider(rpcUrl)
))
}
}, [rpcUrl, provider])
useEffect(() => setAppSizeOnLoad(
(window.performance.getEntriesByType('navigation') as any)[0].transferSize
@ -154,84 +84,16 @@ function App() {
useEffect(() => setNavigateToLogin(false), [initialVisit])
useEffect(() => {
provider?.getNetwork().then(network => {
if (network.chainId === ChainId.SEPOLIA) {
setDotOs(DotOsRegistrar__factory.connect(
DOT_OS_ADDRESSES[ChainId.SEPOLIA],
provider!.getSigner()
))
setKns(KNSRegistryResolver__factory.connect(
KNS_REGISTRY_ADDRESSES[ChainId.SEPOLIA],
provider!.getSigner()
))
setKnsEnsEntry(KNSEnsEntry__factory.connect(
KNS_ENS_ENTRY_ADDRESSES[ChainId.SEPOLIA],
provider!.getSigner()
))
setKnsEnsExit(KNSEnsExit__factory.connect(
KNS_ENS_EXIT_ADDRESSES[ChainId.SEPOLIA],
provider!.getSigner()
))
setNameWrapper(NameWrapper__factory.connect(
NAMEWRAPPER_ADDRESSES[ChainId.SEPOLIA],
provider!.getSigner()
))
setEnsRegistry(ENSRegistry__factory.connect(
ENS_REGISTRY_ADDRESSES[ChainId.SEPOLIA],
provider!.getSigner()
))
} else if (network.chainId === ChainId.OPTIMISM || network.chainId === ChainId.MAINNET) {
setDotOs(DotOsRegistrar__factory.connect(
DOT_OS_ADDRESSES[ChainId.OPTIMISM],
provider!.getSigner())
)
setKns(KNSRegistryResolver__factory.connect(
KNS_REGISTRY_ADDRESSES[ChainId.OPTIMISM],
provider!.getSigner())
)
setKnsEnsExit(KNSEnsExit__factory.connect(
KNS_ENS_EXIT_ADDRESSES[ChainId.OPTIMISM],
provider!.getSigner()
))
setKnsEnsEntry(KNSEnsEntry__factory.connect(
KNS_ENS_ENTRY_ADDRESSES[ChainId.MAINNET],
provider!.getSigner()
))
setNameWrapper(NameWrapper__factory.connect(
NAMEWRAPPER_ADDRESSES[ChainId.MAINNET],
new ethers.providers.JsonRpcProvider(import.meta.env.REACT_APP_MAINNET_RPC_URL)
))
setEnsRegistry(ENSRegistry__factory.connect(
ENS_REGISTRY_ADDRESSES[ChainId.MAINNET],
new ethers.providers.JsonRpcProvider(import.meta.env.REACT_APP_MAINNET_RPC_URL)
))
}
})
}, [provider])
const knsEnsEntryNetwork = ChainId.SEPOLIA;
const knsEnsExitNetwork = ChainId.SEPOLIA;
// just pass all the props each time since components won't mind extras
const props = {
direct, setDirect,
key,
key, appSizeOnLoad,
keyFileName, setKeyFileName,
reset, setReset,
pw, setPw,
knsName, setOsName,
dotOs: dotOs!,
kns: kns!,
knsEnsEntry: knsEnsEntry!,
knsEnsExit: knsEnsExit!,
nameWrapper: nameWrapper!,
ensRegistry: ensRegistry!,
knsEnsEntryNetwork,
knsEnsExitNetwork,
connectOpen, openConnect, closeConnect,
provider, appSizeOnLoad,
networkingKey, setNetworkingKey,
ipAddress, setIpAddress,
ws_port, setWsPort,
@ -242,7 +104,8 @@ function App() {
return (
<>
<ConnectWallet {...props} />
<ConnectButton chainStatus="icon" accountStatus="avatar" />
<Router>
<Routes>
<Route path="/" element={navigateToLogin

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,60 @@
import { multicallAbi, kinomapAbi, mechAbi, KINOMAP, MULTICALL, KINO_ACCOUNT_IMPL } from "./";
import { encodeFunctionData, encodePacked, stringToHex } from "viem";
export function encodeMulticalls(metadataUri: string, metadataHash: string) {
const metadataUriCall = encodeFunctionData({
abi: kinomapAbi,
functionName: 'note',
args: [
encodePacked(["bytes"], [stringToHex("~metadata-uri")]),
encodePacked(["bytes"], [stringToHex(metadataUri)]),
]
})
const metadataHashCall = encodeFunctionData({
abi: kinomapAbi,
functionName: 'note',
args: [
encodePacked(["bytes"], [stringToHex("~metadata-hash")]),
encodePacked(["bytes"], [stringToHex(metadataHash)]),
]
})
const calls = [
{ target: KINOMAP, callData: metadataUriCall },
{ target: KINOMAP, callData: metadataHashCall }
];
const multicall = encodeFunctionData({
abi: multicallAbi,
functionName: 'aggregate',
args: [calls]
});
return multicall;
}
export function encodeIntoMintCall(multicalls: `0x${string}`, our_address: `0x${string}`, app_name: string) {
const initCall = encodeFunctionData({
abi: mechAbi,
functionName: 'execute',
args: [
MULTICALL,
BigInt(0), // value
multicalls,
1
]
});
const mintCall = encodeFunctionData({
abi: kinomapAbi,
functionName: 'mint',
args: [
our_address,
encodePacked(["bytes"], [stringToHex(app_name)]),
initCall,
"0x", // erc721 details? <- encode app_store here? actually might be a slick way to do it.
KINO_ACCOUNT_IMPL,
]
})
return mintCall;
}

View File

@ -0,0 +1,29 @@
import { parseAbi } from "viem";
export { encodeMulticalls, encodeIntoMintCall } from "./helpers";
// move to constants? // also for anvil/optimism
export const KINOMAP: `0x${string}` = "0x0165878A594ca255338adfa4d48449f69242Eb8F";
export const MULTICALL: `0x${string}` = "0xcA11bde05977b3631167028862bE2a173976CA11";
export const KINO_ACCOUNT_IMPL: `0x${string}` = "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9";
export const multicallAbi = parseAbi([
`function aggregate(Call[] calls) external payable returns (uint256 blockNumber, bytes[] returnData)`,
`struct Call { address target; bytes callData; }`,
]);
export const kinomapAbi = parseAbi([
"function mint(address, bytes calldata, bytes calldata, bytes calldata, address) external returns (address tba)",
"function note(bytes calldata,bytes calldata) external returns (bytes32)",
"function get(bytes32 node) external view returns (address tokenBoundAccount, address tokenOwner, bytes memory note)",
]);
export const mechAbi = parseAbi([
"function execute(address to, uint256 value, bytes calldata data, uint8 operation) returns (bytes memory returnData)",
"function token() external view returns (uint256,address,uint256)"
])
// export const public_client =

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,105 +0,0 @@
import { useCallback } from 'react';
import ethLogo from '../assets/eth.png';
import sepoliaLogo from '../assets/sepolia.png';
import optimismLogo from '../assets/optimism.png';
import arbitrumLogo from '../assets/arbitrum.png';
import unknownLogo from '../assets/unknown.png';
import Jazzicon from "./Jazzicon";
import { hooks } from "../connectors/metamask";
import { KNS_REGISTRY_ADDRESSES } from '../constants/addresses';
const { useChainId } = hooks;
interface ChainInfoProps {
account: string;
networkName: string;
changeConnectedAccount: () => void;
changeToNodeChain: () => void;
}
function ChainInfo({
account,
networkName,
changeConnectedAccount,
changeToNodeChain,
}: ChainInfoProps) {
const chainId = useChainId();
const formatAddress = (address: string) => {
return `${address.substring(0, 6)}...${address.substring(
address.length - 4
)}`;
};
const generateNetworkIcon = (networkName: string) => {
switch (networkName) {
case "Ethereum":
return <img className="network-icon" src={ethLogo} alt={networkName} />;
case "Optimism":
return (
<img className="network-icon" src={optimismLogo} alt={networkName} />
);
case "Arbitrum":
return (
<img className="network-icon" src={arbitrumLogo} alt={networkName} />
);
case "Sepolia":
return (
<img
className="network-icon"
src={sepoliaLogo}
alt={networkName}
/>
);
default:
return (
<img
className="network-icon"
src={unknownLogo}
alt={networkName}
/>
);
}
};
const showKnsAddress = useCallback(() => {
window.alert(`The KNS Contract Address is: ${KNS_REGISTRY_ADDRESSES[chainId || ''] || 'unavailable on ' + networkName}`)
}, [chainId, networkName])
return (
<div
className='flex gap-4'
>
{/* TODO: prompt to change address */}
<button
onClick={changeConnectedAccount}
className="font-mono clear flex place-items-center max-w-1/3"
>
<Jazzicon
address={account || ""}
diameter={24}
className='mr-4'
/>{" "}
{formatAddress(account || "")}
</button>
<button
onClick={changeToNodeChain}
className="clear max-w-1/3 z-10"
>
{generateNetworkIcon(networkName)}
<div className='ml-2'>
{networkName}
</div>
</button>
{/* TODO: show KNS contract ID in modal */}
<button
onClick={showKnsAddress}
className="clear max-w-1/3"
>
KNS Contract
</button>
</div>
);
}
export default ChainInfo;

View File

@ -1,62 +0,0 @@
import { useCallback } from 'react';
import { hooks, metaMask } from "../connectors/metamask";
import Modal from "react-modal"
import { SEPOLIA_OPT_HEX, SEPOLIA_OPT_INT } from '../constants/chainId';
const {
useIsActivating,
} = hooks;
type ConnectWalletProps = {
connectOpen: boolean,
closeConnect: () => void
}
export default function ConnectWallet({ connectOpen, closeConnect }: ConnectWalletProps) {
const isActivating = useIsActivating();
const connect = useCallback(async () => {
closeConnect()
await metaMask.activate().catch(() => { })
try {
const networkId = String(await (window.ethereum as any)?.request({ method: 'net_version' }).catch(() => '0x1'))
if (networkId !== SEPOLIA_OPT_HEX && networkId !== SEPOLIA_OPT_INT) {
const SEPOLIA_DETAILS = {
chainId: '0xaa36a7',
chainName: 'Sepolia Test Network',
nativeCurrency: {
name: 'Ethereum',
symbol: 'ETH',
decimals: 18
},
rpcUrls: ['https://sepolia-infura.brave.com/'], // Replace with Sepolia's RPC URL
blockExplorerUrls: ['https://sepolia.etherscan.io'] // Replace with Sepolia's block explorer URL
};
await (window.ethereum as any)?.request({
method: 'wallet_addEthereumChain',
params: [SEPOLIA_DETAILS]
})
}
} catch (err) {
console.error('FAILED TO ADD SEPOLIA:', err)
}
}, [closeConnect]);
return (
<Modal
isOpen={connectOpen}
onRequestClose={closeConnect}
className="connect-modal"
overlayClassName="overlay-modal"
>
<div className="connect-modal-content">
<button onClick={connect} disabled={isActivating} >
Connect to Wallet
</button>
</div>
</Modal>
);
}

View File

@ -1,21 +1,14 @@
import React, { useEffect, useRef } from "react";
import { hooks } from "../connectors/metamask";
import { NameWrapper, ENSRegistry } from "../abis/types";
import isValidDomain from 'is-valid-domain'
import { hash } from '@ensdomains/eth-ens-namehash';
import { toAscii } from 'idna-uts46-hx'
const {
useAccount,
} = hooks;
import { useAccount } from "wagmi";
type ClaimOsNameProps = {
name: string,
setName: React.Dispatch<React.SetStateAction<string>>
nameValidities: string[],
setNameValidities: React.Dispatch<React.SetStateAction<string[]>>,
nameWrapper: NameWrapper,
ensRegistry: ENSRegistry,
triggerNameCheck: boolean
}
@ -24,14 +17,12 @@ function EnterEthName({
setName,
nameValidities,
setNameValidities,
nameWrapper,
ensRegistry,
triggerNameCheck
}: ClaimOsNameProps) {
const userAddress = useAccount()
const { address } = useAccount()
console.log("userAddress", userAddress)
console.log("userAddress", address)
const NAME_URL = "Name must be a valid URL without subdomains (A-Z, a-z, 0-9, and punycode)"
const NAME_NOT_OWNED = "Name is not owned by your wallet"
@ -71,12 +62,13 @@ function EnterEthName({
index = validities.indexOf(NAME_NOT_OWNED)
if (validities.length == 0 || index != -1) {
let owner = await ensRegistry.owner(hash(normalized))
// TODO
let owner = "ensRegistry.owner(hash(normalized))" // await ensRegistry.owner(hash(normalized))
if (owner == nameWrapper.address)
owner = await nameWrapper.ownerOf(hash(normalized))
// if (owner == nameWrapper.address)
// owner = await nameWrapper.ownerOf(hash(normalized))
if (owner != userAddress) {
if (owner != address) {
if (index == -1) validities.push(NAME_NOT_OWNED)
} else {
validities.splice(index, 1)

View File

@ -1,5 +1,4 @@
import React, { useEffect, useRef } from "react";
import { DotOsRegistrar } from "../abis/types";
import isValidDomain from "is-valid-domain";
import hash from "@ensdomains/eth-ens-namehash";
import { toAscii } from "idna-uts46-hx";
@ -9,7 +8,6 @@ type ClaimOsNameProps = {
setName: React.Dispatch<React.SetStateAction<string>>;
nameValidities: string[];
setNameValidities: React.Dispatch<React.SetStateAction<string[]>>;
dotOs?: DotOsRegistrar;
triggerNameCheck: boolean;
isReset?: boolean;
};
@ -19,7 +17,6 @@ function EnterKnsName({
setName,
nameValidities,
setNameValidities,
dotOs,
triggerNameCheck,
isReset = false,
}: ClaimOsNameProps) {
@ -67,7 +64,8 @@ function EnterKnsName({
if (validities.length === 0 || index !== -1 && normalized.length > 2) {
try {
const namehash = hash.hash(normalized)
const owner = await dotOs?.ownerOf(namehash);
// TODO
const owner = "dotOs.ownerOf(namehash)" // await dotOs?.ownerOf(namehash);
if (owner && index === -1) validities.push(NAME_CLAIMED);
} catch (e) {
console.error({ e })

View File

@ -1,150 +0,0 @@
import { useWeb3React } from "@web3-react/core";
import { hooks, metaMask } from "../connectors/metamask";
import { ReactNode, useCallback, useEffect, useState } from "react";
import Loader from "./Loader";
import { getNetworkName, setChain } from "../utils/chain";
import ChainInfo from "./ChainInfo";
import { OPTIMISM_OPT_HEX, SEPOLIA_OPT_HEX } from "../constants/chainId";
import sepoliaLogo from "../assets/sepolia.png";
import optimismLogo from "../assets/optimism.png";
import { Tooltip } from "./Tooltip";
import { isMobileCheck } from "../utils/dimensions";
import classNames from "classnames";
const { useIsActivating, useChainId } = hooks;
type KinodeHeaderProps = {
header: ReactNode;
nameLogo?: boolean;
nodeChainId: string;
openConnect: () => void;
closeConnect: () => void;
hideConnect?: boolean;
};
function KinodeHeader({
header,
closeConnect,
nodeChainId,
hideConnect = false,
}: KinodeHeaderProps) {
const { account, isActive } = useWeb3React();
const isActivating = useIsActivating();
const chainId = useChainId();
const [networkName, setNetworkName] = useState("");
useEffect(() => {
setNetworkName(getNetworkName(chainId?.toString()));
}, [chainId]);
const connectWallet = useCallback(async () => {
closeConnect();
await metaMask.activate();
setChain(nodeChainId);
}, [closeConnect, nodeChainId]);
const changeToNodeChain = useCallback(async () => {
// If correct ndetwork is set, just say that
if (chainId) {
const hexChainId = "0x" + chainId.toString(16);
if (hexChainId === nodeChainId) {
return alert(
`You are already connected to ${getNetworkName(chainId.toString())}`
);
}
setChain(nodeChainId);
}
}, [chainId, nodeChainId]);
const changeConnectedAccount = useCallback(async () => {
alert("You can change your connected account in your wallet.");
}, []);
const isMobile = isMobileCheck()
return (
<>
<div id="signup-form-header" className="flex flex-col">
{(nodeChainId === SEPOLIA_OPT_HEX ||
nodeChainId === OPTIMISM_OPT_HEX) && (
<Tooltip
position="left"
className={classNames("!absolute z-10", {
'top-8 right-8': !isMobile,
'top-2 right-2': isMobile
})}
button={nodeChainId === SEPOLIA_OPT_HEX ? (
<img
alt="sepolia"
className="network-icon"
src={sepoliaLogo}
/>
) : nodeChainId === OPTIMISM_OPT_HEX ? (
<img
alt="optimism"
className="network-icon"
src={optimismLogo}
/>
) : 'Not connected'}
text={nodeChainId === SEPOLIA_OPT_HEX
? `Your Kinode is currently pointed at Sepolia. To point at Optimism, boot without the "--testnet" flag.`
: nodeChainId === OPTIMISM_OPT_HEX
? `Your Kinode is currently pointed at Optimism. To point at Sepolia, boot with the "--testnet" flag.`
: 'Your Kinode is not pointed at a chain.'}
/>
)}
<div className="flex flex-col gap-4 c">
{header}
</div>
{!hideConnect && (
<div
className="flex c w-[99vw] mb-8 absolute top-2 left-2"
>
{isActive && account ? (
<ChainInfo
account={account}
networkName={networkName}
changeToNodeChain={changeToNodeChain}
changeConnectedAccount={changeConnectedAccount}
/>
) : (
<div className="flex flex-col gap-8 my-4">
<h5 className={classNames("flex c", {
'flex-wrap text-center max-w-3/4 gap-2': isMobile
})}>
{!isActivating && 'You must connect to a browser wallet to continue.'}
{isActivating ? (
<Loader msg="Approve connection in your wallet" />
) : (
<button onClick={connectWallet} className="ml-2"> Connect Wallet </button>
)}
</h5>
{nodeChainId === SEPOLIA_OPT_HEX && (
<h5
className="text-center max-w-[450px] leading-6 flex c"
>
Kinode is currently on the Sepolia Testnet.
<a
href="https://sepoliafaucet.com/"
target="_blank"
rel="noreferrer"
className="button alt ml-2"
>
Get Testnet ETH
</a>
</h5>
)}
</div>
)}
</div>
)}
</div>
</>
);
}
export default KinodeHeader;

View File

@ -1,4 +0,0 @@
import { initializeConnector } from '@web3-react/core'
import { MetaMask } from '@web3-react/metamask'
export const [metaMask, hooks] = initializeConnector<MetaMask>((actions) => new MetaMask({ actions }))

View File

@ -1,28 +1,52 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import ReactDOM from 'react-dom/client'
import App from './App';
import { Web3ReactProvider, Web3ReactHooks } from '@web3-react/core';
import { hooks as metaMaskHooks, metaMask } from './connectors/metamask'
import type { MetaMask } from '@web3-react/metamask'
import '@unocss/reset/tailwind.css'
// import '@unocss/reset/tailwind.css'
// import '@rainbow-me/rainbowkit/styles.css';
import 'uno.css'
import './index.css';
import {
getDefaultConfig,
RainbowKitProvider,
} from '@rainbow-me/rainbowkit';
import { WagmiProvider, http } from 'wagmi';
import {
optimism,
anvil
} from 'wagmi/chains';
import {
QueryClientProvider,
QueryClient,
} from "@tanstack/react-query";
import { Buffer } from 'buffer';
window.Buffer = Buffer;
const connectors: [MetaMask, Web3ReactHooks][] = [
[metaMask, metaMaskHooks],
]
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
const config = getDefaultConfig({
appName: 'Kinode Register UI',
projectId: 'YOUR_PROJECT_ID', // apparently need project_Id if using wallet_connect
chains: [anvil], // change back to OP main once ready
ssr: false, // If your dApp uses server side rendering (SSR)
transports: {
[anvil.id]: http("http://localhost:8545")
}
});
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<Web3ReactProvider connectors={connectors}>
<div id="signup-page" className="flex flex-col place-items-center place-content-center h-screen w-screen">
<App />
</div>
</Web3ReactProvider>
</React.StrictMode>
);
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>
<App />
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
</React.StrictMode>,
)

View File

@ -1,5 +1,3 @@
import { ethers } from "ethers";
import { KNSEnsEntry, KNSEnsExit, NameWrapper, ENSRegistry, KNSRegistryResolver, DotOsRegistrar } from "../abis/types";
export interface PageProps {
networkingKey: string,
@ -24,17 +22,9 @@ export interface PageProps {
setReset: React.Dispatch<React.SetStateAction<boolean>>,
pw: string,
setPw: React.Dispatch<React.SetStateAction<string>>,
dotOs: DotOsRegistrar,
kns: KNSRegistryResolver,
knsEnsEntryNetwork: number,
knsEnsEntry: KNSEnsEntry,
knsEnsExit: KNSEnsExit,
nameWrapper: NameWrapper,
ensRegistry: ENSRegistry,
connectOpen: boolean,
openConnect: () => void,
closeConnect: () => void,
provider?: ethers.providers.Web3Provider,
appSizeOnLoad: number,
nodeChainId: string
}

View File

@ -1,17 +1,16 @@
import { useState, useEffect, FormEvent } from "react";
import { hooks } from "../connectors/metamask";
import { Link, useNavigate } from "react-router-dom";
import EnterKnsName from "../components/EnterKnsName";
import Loader from "../components/Loader";
import KinodeHeader from "../components/KnsHeader";
import { NetworkingInfo, PageProps } from "../lib/types";
import { ipToNumber } from "../utils/ipToNumber";
import DirectCheckbox from "../components/DirectCheckbox";
import { KinodeTitle } from "../components/KinodeTitle";
import { Tooltip } from "../components/Tooltip";
import { getFetchUrl } from "../utils/fetch";
import { useAccount, useSignMessage } from "wagmi";
const { useAccounts, useProvider } = hooks;
// Todo: further revamp!
interface ClaimOsNameProps extends PageProps { }
@ -19,19 +18,16 @@ function ClaimOsInvite({
direct,
setDirect,
setOsName,
dotOs,
openConnect,
setNetworkingKey,
setIpAddress,
setWsPort,
setTcpPort,
setRouters,
closeConnect,
nodeChainId,
}: ClaimOsNameProps) {
const accounts = useAccounts();
const provider = useProvider();
const { address } = useAccount();
const navigate = useNavigate();
const { data: signMessageData, error, signMessage, variables } = useSignMessage()
const [isLoading, setIsLoading] = useState(false);
const [loaderMsg, setLoaderMsg] = useState("");
@ -45,7 +41,7 @@ function ClaimOsInvite({
document.title = "Claim Invite";
}, []);
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [provider]); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [address]); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => {
(async () => {
@ -67,7 +63,6 @@ function ClaimOsInvite({
e.preventDefault();
e.stopPropagation();
if (!provider) return openConnect();
const {
networking_key,
@ -113,7 +108,7 @@ function ClaimOsInvite({
credentials: 'include',
body: JSON.stringify({
name: name + ".os",
address: accounts![0],
address,
networkingKey: networking_key,
wsIp: ipAddress,
wsPort: ws_port,
@ -137,10 +132,12 @@ function ClaimOsInvite({
const data = await response.json();
const uint8Array = new Uint8Array(Object.values(data.message));
const signer = await provider?.getSigner();
const signature = await signer?.signMessage(uint8Array);
// const uint8Array = new Uint8Array(Object.values(data.message));
// doublecheck and fix this
signMessage({
message: data,
});
const signature = signMessageData;
data.userOperation.signature = signature;
@ -153,7 +150,7 @@ function ClaimOsInvite({
userOp: data.userOperation,
code: invite,
name: name + ".os",
eoa: accounts![0],
eoa: address,
}),
});
} catch (e) {
@ -175,66 +172,57 @@ function ClaimOsInvite({
setName,
nameValidities,
setNameValidities,
dotOs,
triggerNameCheck,
};
return (
<>
<KinodeHeader
header={<KinodeTitle prefix="Claim Invite" />}
openConnect={openConnect}
closeConnect={closeConnect}
nodeChainId={nodeChainId}
/>
{Boolean(provider) && (
<form id="signup-form" className="flex flex-col" onSubmit={handleRegister}>
{isLoading ? (
<Loader msg={loaderMsg} />
) : (
<>
<div className="flex c mb-2">
<h5>Set up your Kinode with a .os name</h5>
<Tooltip text={`Kinodes use a .os name in order to identify themselves to other nodes in the network.`} />
</div>
<div className="flex flex-col mb-2">
<input
value={invite}
onChange={(e) => setInvite(e.target.value)}
type="text"
required
name="nec-invite"
placeholder="invite code"
className="self-stretch"
/>
{inviteValidity !== "" && (
<div className="invite-validity">{inviteValidity}</div>
)}
</div>
<form id="signup-form" className="flex flex-col" onSubmit={handleRegister}>
{isLoading ? (
<Loader msg={loaderMsg} />
) : (
<>
<div className="flex c mb-2">
<h5>Set up your Kinode with a .os name</h5>
<Tooltip text={`Kinodes use a .os name in order to identify themselves to other nodes in the network.`} />
</div>
<h3 className="mb-2">
<EnterKnsName {...enterOsNameProps} />
</h3>
<div className="flex flex-col mb-2">
<input
value={invite}
onChange={(e) => setInvite(e.target.value)}
type="text"
required
name="nec-invite"
placeholder="invite code"
className="self-stretch"
/>
{inviteValidity !== "" && (
<div className="invite-validity">{inviteValidity}</div>
)}
</div>
<DirectCheckbox {...{ direct, setDirect }} />
<h3 className="mb-2">
<EnterKnsName {...enterOsNameProps} />
</h3>
<button
disabled={nameValidities.length !== 0 || inviteValidity !== ""}
type="submit"
className="self-stretch mt-2"
>
Register .os name
</button>
<DirectCheckbox {...{ direct, setDirect }} />
<Link to="/reset" className="button clear">
already have a .os?
</Link>
</>
)}
</form >
)
}
<button
disabled={nameValidities.length !== 0 || inviteValidity !== ""}
type="submit"
className="self-stretch mt-2"
>
Register .os name
</button>
<Link to="/reset" className="button clear">
already have a .os?
</Link>
</>
)}
</form >
</>
);
}

View File

@ -5,21 +5,17 @@ import {
useRef,
useState,
} from "react";
import { utils } from "ethers";
import KinodeHeader from "../components/KnsHeader";
import { PageProps } from "../lib/types";
import Loader from "../components/Loader";
import { getFetchUrl } from "../utils/fetch";
import { sha256, toBytes } from "viem";
interface ImportKeyfileProps extends PageProps { }
function ImportKeyfile({
pw,
setPw,
openConnect,
appSizeOnLoad,
closeConnect,
nodeChainId,
}: ImportKeyfileProps) {
const [localKey, setLocalKey] = useState<string>("");
@ -127,7 +123,7 @@ function ImportKeyfile({
try {
if (keyErrs.length === 0 && localKey !== "") {
let hashed_password = utils.sha256(utils.toUtf8Bytes(pw));
let hashed_password = sha256(toBytes(pw));
const response = await fetch(getFetchUrl("/vet-keyfile"), {
method: "POST",
@ -178,13 +174,6 @@ function ImportKeyfile({
return (
<>
<KinodeHeader
header={<h1>Import Keyfile</h1>}
openConnect={openConnect}
closeConnect={closeConnect}
hideConnect
nodeChainId={nodeChainId}
/>
{loading ? (
<Loader msg="Setting up node..." />
) : (

View File

@ -1,18 +1,13 @@
import { useEffect } from "react"
import { useNavigate } from "react-router-dom"
import KinodeHeader from "../components/KnsHeader"
import { OPTIMISM_OPT_HEX } from "../constants/chainId";
import { KinodeTitle } from "../components/KinodeTitle";
type OsHomeProps = {
openConnect: () => void
provider: any
knsName: string
closeConnect: () => void
nodeChainId: string
}
function KinodeHome({ openConnect, knsName, closeConnect, nodeChainId }: OsHomeProps) {
function KinodeHome({ knsName, nodeChainId }: OsHomeProps) {
const navigate = useNavigate()
const inviteRedir = () => navigate('/claim-invite')
const registerEthRedir = () => navigate('/register-eth-name')
@ -31,7 +26,6 @@ function KinodeHome({ openConnect, knsName, closeConnect, nodeChainId }: OsHomeP
return (
<>
<KinodeHeader header={<KinodeTitle prefix="Welcome to" showLogo />} openConnect={openConnect} closeConnect={closeConnect} hideConnect nodeChainId={nodeChainId} nameLogo />
<div className="flex flex-col max-w-[460px] w-full gap-4 mt-8">
{previouslyBooted ? (
<button onClick={loginRedir}> Login </button>

View File

@ -1,21 +1,17 @@
import { FormEvent, useCallback, useEffect, useState } from "react";
import { namehash } from "ethers/lib/utils";
import { utils } from "ethers";
import KinodeHeader from "../components/KnsHeader";
import { PageProps, UnencryptedIdentity } from "../lib/types";
import Loader from "../components/Loader";
import { hooks } from "../connectors/metamask";
import { downloadKeyfile } from "../utils/download-keyfile";
import DirectCheckbox from "../components/DirectCheckbox";
import { useNavigate } from "react-router-dom";
import { Tooltip } from "../components/Tooltip";
import { KinodeTitle } from "../components/KinodeTitle";
import { isMobileCheck } from "../utils/dimensions";
import classNames from "classnames";
import { generateNetworkingKeys, getNetworkName } from "../utils/chain";
import { getFetchUrl } from "../utils/fetch";
const { useProvider } = hooks;
import { useAccount } from "wagmi";
import { sha256, toBytes } from "viem";
interface LoginProps extends PageProps { }
@ -24,10 +20,8 @@ function Login({
setDirect,
pw,
setPw,
kns,
openConnect,
appSizeOnLoad,
closeConnect,
routers,
setNetworkingKey,
setIpAddress,
@ -38,8 +32,8 @@ function Login({
setOsName,
nodeChainId,
}: LoginProps) {
const provider = useProvider();
const navigate = useNavigate()
const address = useAccount();
const [keyErrs, setKeyErrs] = useState<string[]>([]);
const [loading, setLoading] = useState<string>("");
@ -71,7 +65,7 @@ function Login({
try {
if (reset) {
if (!provider) {
if (!address) {
setKeyErrs(["Please connect your wallet and try again"]);
setRestartFlow(true);
return openConnect();
@ -79,7 +73,7 @@ function Login({
setLoading("Checking password...");
let hashed_password = utils.sha256(utils.toUtf8Bytes(pw));
let hashed_password = sha256(toBytes(pw));
// Replace this with network key generation
const response = await fetch(getFetchUrl("/vet-keyfile"), {
@ -96,10 +90,10 @@ function Login({
// Generate keys on server that are stored temporarily
const data = await generateNetworkingKeys({
direct,
kns,
kns: "kns here",
nodeChainId,
chainName: getNetworkName(nodeChainId),
nameToSet: namehash(knsName),
nameToSet: "namehash(knsName)",
setNetworkingKey,
setIpAddress,
setWsPort,
@ -107,17 +101,17 @@ function Login({
setRouters,
})
setLoading("Please confirm the transaction");
// setLoading("Please confirm the transaction");
const tx = await kns.multicall(data);
// const tx = await kns.multicall(data);
setLoading("Resetting Networking Information...");
// setLoading("Resetting Networking Information...");
await tx.wait();
// await tx.wait();
}
setLoading("Logging in...");
let hashed_password = utils.sha256(utils.toUtf8Bytes(pw));
let hashed_password = sha256(toBytes(pw));
// Login or confirm new keys
const result = await fetch(
@ -163,7 +157,7 @@ function Login({
setLoading("");
}
},
[pw, appSizeOnLoad, reset, direct, knsName, provider, openConnect, kns]
[pw, appSizeOnLoad, reset, direct, knsName, openConnect]
);
const isDirect = Boolean(routers?.length === 0);
@ -172,13 +166,6 @@ function Login({
return (
<>
<KinodeHeader
header={<KinodeTitle prefix='Login to' showLogo />}
openConnect={openConnect}
closeConnect={closeConnect}
hideConnect={!showReset}
nodeChainId={nodeChainId}
/>
{loading ? (
<Loader msg={loading} />
) : (

View File

@ -1,11 +1,8 @@
import { useState, useEffect, FormEvent, useCallback } from "react";
import { hooks } from "../connectors/metamask";
import { useNavigate } from "react-router-dom";
import { toDNSWireFormat } from "../utils/dnsWire";
import { utils } from "ethers";
import EnterEthName from "../components/EnterEthName";
import Loader from "../components/Loader";
import KinodeHeader from "../components/KnsHeader";
import { PageProps } from "../lib/types";
import { generateNetworkingKeys, getNetworkName, setChain } from "../utils/chain";
import { hash } from "@ensdomains/eth-ens-namehash";
@ -13,7 +10,7 @@ import DirectCheckbox from "../components/DirectCheckbox";
import { MAINNET_OPT_HEX, OPTIMISM_OPT_HEX } from "../constants/chainId";
import { KinodeTitle } from "../components/KinodeTitle";
const { useAccounts } = hooks;
import { useAccount } from "wagmi";
interface RegisterOsNameProps extends PageProps { }
@ -21,12 +18,7 @@ function RegisterEthName({
direct,
setDirect,
setOsName,
nameWrapper,
ensRegistry,
knsEnsEntry,
kns,
openConnect,
provider,
closeConnect,
setNetworkingKey,
setIpAddress,
@ -35,7 +27,7 @@ function RegisterEthName({
setRouters,
nodeChainId,
}: RegisterOsNameProps) {
let accounts = useAccounts();
let { address } = useAccount();
let navigate = useNavigate();
const chainName = getNetworkName(nodeChainId);
const [loading, setLoading] = useState("");
@ -49,15 +41,13 @@ function RegisterEthName({
document.title = "Register";
}, []);
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [provider]); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [address]); // eslint-disable-line react-hooks/exhaustive-deps
const enterEthNameProps = {
name,
setName,
nameValidities,
setNameValidities,
nameWrapper,
ensRegistry,
triggerNameCheck,
};
@ -66,17 +56,16 @@ function RegisterEthName({
e.preventDefault();
e.stopPropagation();
if (!provider) return openConnect();
setLoading("Please confirm the transaction in your wallet");
try {
const cleanedName = name.trim().replace(".eth", "");
const nameToSet = utils.namehash(`${cleanedName}.eth`);
const nameToSet = "namehash(`${cleanedName}.eth`)";
const targetChainId = nodeChainId === OPTIMISM_OPT_HEX ? MAINNET_OPT_HEX : nodeChainId;
const data = await generateNetworkingKeys({
direct,
kns,
kns: "kns here",
nodeChainId: targetChainId,
chainName,
nameToSet,
@ -94,22 +83,22 @@ function RegisterEthName({
const dnsFormat = toDNSWireFormat(`${cleanedName}.eth`);
const hashedName = hash(`${cleanedName}.eth`);
const tx = await knsEnsEntry.setKNSRecords(dnsFormat, data, { gasLimit: 300000 });
// const tx = await knsEnsEntry.setKNSRecords(dnsFormat, data, { gasLimit: 300000 });
const onRegistered = (node: any, _name: any) => {
if (node === hashedName) {
kns.off("NodeRegistered", onRegistered);
setLoading("");
setOsName(`${cleanedName}.eth`);
navigate("/set-password");
}
};
// const onRegistered = (node: any, _name: any) => {
// if (node === hashedName) {
// kns.off("NodeRegistered", onRegistered);
// setLoading("");
// setOsName(`${cleanedName}.eth`);
// navigate("/set-password");
// }
// };
await setChain(nodeChainId);
// await setChain(nodeChainId);
setLoading(`Registering ${cleanedName}.eth on Kinode... this may take a few minutes.`);
kns.on("NodeRegistered", onRegistered);
await tx.wait();
// setLoading(`Registering ${cleanedName}.eth on Kinode... this may take a few minutes.`);
// kns.on("NodeRegistered", onRegistered);
// await tx.wait();
} catch (error) {
console.error("Registration Error:", error);
setLoading("");
@ -121,11 +110,8 @@ function RegisterEthName({
[
name,
direct,
accounts,
kns,
navigate,
setOsName,
provider,
openConnect,
setNetworkingKey,
setIpAddress,
@ -139,13 +125,8 @@ function RegisterEthName({
return (
<>
<KinodeHeader
header={<KinodeTitle prefix="Register via ENS" />}
openConnect={openConnect}
closeConnect={closeConnect}
nodeChainId={nodeChainId === OPTIMISM_OPT_HEX ? MAINNET_OPT_HEX : nodeChainId}
/>
{Boolean(provider) && (
{Boolean(address) && (
<form id="signup-form" className="flex flex-col" onSubmit={handleRegister}>
{loading ? (
<Loader msg={loading} />

View File

@ -1,20 +1,15 @@
import { useState, useEffect, FormEvent, useCallback } from "react";
import { hooks } from "../connectors/metamask";
import { Link, useNavigate } from "react-router-dom";
import { toDNSWireFormat } from "../utils/dnsWire";
import { utils } from 'ethers';
import EnterKnsName from "../components/EnterKnsName";
import Loader from "../components/Loader";
import KinodeHeader from "../components/KnsHeader";
import { PageProps } from "../lib/types";
import { generateNetworkingKeys, getNetworkName } from "../utils/chain";
import DirectCheckbox from "../components/DirectCheckbox";
import { Tooltip } from "../components/Tooltip";
const {
useAccounts,
} = hooks;
import { useAccount } from "wagmi";
interface RegisterOsNameProps extends PageProps { }
@ -22,10 +17,7 @@ function RegisterKnsName({
direct,
setDirect,
setOsName,
dotOs,
kns,
openConnect,
provider,
closeConnect,
setNetworkingKey,
setIpAddress,
@ -34,7 +26,7 @@ function RegisterKnsName({
setRouters,
nodeChainId,
}: RegisterOsNameProps) {
let accounts = useAccounts();
let { address } = useAccount();
let navigate = useNavigate();
const chainName = getNetworkName(nodeChainId);
const [loading, setLoading] = useState('');
@ -48,23 +40,23 @@ function RegisterKnsName({
document.title = "Register"
}, [])
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [provider]) // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [address]) // eslint-disable-line react-hooks/exhaustive-deps
const enterOsNameProps = { name, setName, nameValidities, setNameValidities, dotOs, triggerNameCheck }
const enterOsNameProps = { name, setName, nameValidities, setNameValidities, triggerNameCheck }
let handleRegister = useCallback(async (e: FormEvent) => {
e.preventDefault()
e.stopPropagation()
if (!provider || !kns) return openConnect()
setLoading('Please confirm the transaction in your wallet');
try {
const nameToSet = utils.namehash(`${name}.os`);
// TODO
const nameToSet = "namehash(`${name}.os`)" // utils.namehash(`${name}.os`);
const data = await generateNetworkingKeys({
direct,
kns,
kns: "kns here",
nodeChainId,
chainName,
nameToSet,
@ -76,16 +68,16 @@ function RegisterKnsName({
});
const dnsFormat = toDNSWireFormat(`${name}.os`);
const tx = await dotOs?.register(
dnsFormat,
accounts![0],
data
)
// const tx = await dotOs?.register(
// dnsFormat,
// accounts![0],
// data
// )
setLoading('Registering KNS ID...');
await tx?.wait();
setLoading('');
// await tx?.wait();
// setLoading('');
setOsName(`${name}.os`);
navigate("/set-password");
} catch (error) {
@ -93,20 +85,12 @@ function RegisterKnsName({
setLoading('');
alert('There was an error registering your dot-os-name, please try again.')
}
}, [name, direct, accounts, dotOs, kns, navigate, setOsName, provider, openConnect, setNetworkingKey, setIpAddress, setWsPort, setTcpPort, setRouters, nodeChainId, chainName])
}, [name, direct, address, navigate, setOsName, openConnect, setNetworkingKey, setIpAddress, setWsPort, setTcpPort, setRouters, nodeChainId, chainName])
return (
<>
<KinodeHeader header={<h1
className="flex place-content-center place-items-center mb-4"
>
Register Kinode Name (KNS)
</h1>}
openConnect={openConnect}
closeConnect={closeConnect}
nodeChainId={nodeChainId}
/>
{Boolean(provider) && <form
{Boolean(address) && <form
id="signup-form"
className="flex flex-col w-full max-w-[450px]"
onSubmit={handleRegister}

View File

@ -5,13 +5,11 @@ import {
useRef,
useState,
} from "react";
import { hooks } from "../connectors/metamask";
import { useNavigate } from "react-router-dom";
import { toAscii } from "idna-uts46-hx";
import { hash } from "@ensdomains/eth-ens-namehash";
import isValidDomain from "is-valid-domain";
import Loader from "../components/Loader";
import KinodeHeader from "../components/KnsHeader";
import { PageProps } from "../lib/types";
import { generateNetworkingKeys, getNetworkName } from "../utils/chain";
import { Tooltip } from "../components/Tooltip";
@ -20,13 +18,14 @@ import EnterKnsName from "../components/EnterKnsName";
import { KinodeTitle } from "../components/KinodeTitle";
import { namehash } from "@ethersproject/hash";
import { useAccount } from "wagmi";
const NAME_INVALID_PUNY = "Unsupported punycode character";
const NAME_NOT_OWNER = "Name does not belong to this wallet";
const NAME_NOT_REGISTERED = "Name is not registered";
const NAME_URL =
"Name must be a valid URL without subdomains (A-Z, a-z, 0-9, and punycode)";
const { useAccounts, useProvider } = hooks;
interface ResetProps extends PageProps { }
@ -36,8 +35,6 @@ function Reset({
setReset,
knsName,
setOsName,
dotOs,
kns,
openConnect,
closeConnect,
setNetworkingKey,
@ -47,8 +44,7 @@ function Reset({
setRouters,
nodeChainId,
}: ResetProps) {
const accounts = useAccounts();
const provider = useProvider();
const { address } = useAccount();
const navigate = useNavigate();
const chainName = getNetworkName(nodeChainId);
@ -64,7 +60,7 @@ function Reset({
}, []);
// so inputs will validate once wallet is connected
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [provider]); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => setTriggerNameCheck(!triggerNameCheck), [address]); // eslint-disable-line react-hooks/exhaustive-deps
const nameDebouncer = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
@ -73,7 +69,6 @@ function Reset({
nameDebouncer.current = setTimeout(async () => {
setNameVets([]);
if (!provider) return;
if (name === "") return;
@ -97,12 +92,13 @@ function Reset({
} else if (index !== -1) vets.splice(index, 1);
try {
const owner = await dotOs?.ownerOf(hash(normalized));
// TODO
const owner = "dotOs.ownerOf(hash(normalized))" // await dotOs?.ownerOf(hash(normalized));
index = vets.indexOf(NAME_NOT_OWNER);
if (owner === accounts![0] && index !== -1) vets.splice(index, 1);
else if (index === -1 && owner !== accounts![0])
vets.push(NAME_NOT_OWNER);
// index = vets.indexOf(NAME_NOT_OWNER);
// if (owner === address && index !== -1) vets.splice(index, 1);
// else if (index === -1 && owner !== accounts![0])
// vets.push(NAME_NOT_OWNER);
index = vets.indexOf(NAME_NOT_REGISTERED);
if (index !== -1) vets.splice(index, 1);
@ -123,14 +119,14 @@ function Reset({
e.preventDefault();
e.stopPropagation();
if (!provider || !kns) return openConnect();
setLoading("Please confirm the transaction in your wallet");
try {
const nameToSet = namehash(knsName);
// TODO
const data = await generateNetworkingKeys({
direct,
kns,
kns: "kns here",
nodeChainId,
chainName,
nameToSet,
@ -141,11 +137,11 @@ function Reset({
setRouters,
});
const tx = await kns.multicall(data);
// const tx = await kns.multicall(data);
setLoading("Resetting Networking Information...");
await tx.wait();
// await tx.wait();
setReset(true);
setDirect(direct);
@ -157,13 +153,11 @@ function Reset({
}
},
[
provider,
knsName,
setReset,
setDirect,
navigate,
openConnect,
kns,
direct,
setNetworkingKey,
setIpAddress,
@ -177,12 +171,8 @@ function Reset({
return (
<>
<KinodeHeader header={<KinodeTitle prefix="Reset KNS Name" />}
openConnect={openConnect}
closeConnect={closeConnect}
nodeChainId={nodeChainId}
/>
{Boolean(provider) && (
{Boolean(address) && (
<form id="signup-form" className="flex flex-col" onSubmit={handleResetRecords}>
{loading ? (
<Loader msg={loading} />
@ -193,7 +183,7 @@ function Reset({
Specify the node ID to reset
<Tooltip text={`Kinodes use a .os name in order to identify themselves to other nodes in the network.`} />
</label>
<EnterKnsName {...{ name, setName, nameVets, dotOs, triggerNameCheck, nameValidities, setNameValidities, isReset: true }} />
<EnterKnsName {...{ name, setName, nameVets, triggerNameCheck, nameValidities, setNameValidities, isReset: true }} />
</h3>
<DirectCheckbox {...{ direct, setDirect }} />

View File

@ -4,16 +4,14 @@ import {
useEffect,
useState,
} from "react";
import { hooks } from "../connectors/metamask";
import { Link, useNavigate } from "react-router-dom";
import Loader from "../components/Loader";
import KinodeHeader from "../components/KnsHeader";
import { PageProps } from "../lib/types";
import { generateNetworkingKeys, getNetworkName } from "../utils/chain";
import DirectCheckbox from "../components/DirectCheckbox";
import { namehash } from "@ethersproject/hash";
const { useProvider } = hooks;
import { useAccount } from "wagmi";
interface ResetProps extends PageProps { }
@ -22,9 +20,7 @@ function ResetNode({
setDirect,
setReset,
knsName,
kns,
openConnect,
closeConnect,
setNetworkingKey,
setIpAddress,
setWsPort,
@ -32,7 +28,7 @@ function ResetNode({
setRouters,
nodeChainId,
}: ResetProps) {
const provider = useProvider();
const { address } = useAccount();
const navigate = useNavigate();
const chainName = getNetworkName(nodeChainId);
@ -49,13 +45,13 @@ function ResetNode({
e.preventDefault();
e.stopPropagation();
if (!provider) return openConnect();
setLoading("Please confirm the transaction in your wallet");
try {
// TODO
const data = await generateNetworkingKeys({
direct,
kns,
kns: "kns here",
nodeChainId,
chainName,
nameToSet: namehash(knsName),
@ -66,11 +62,11 @@ function ResetNode({
setRouters,
});
const tx = await kns.multicall(data);
// const tx = await kns.multicall(data);
setLoading("Resetting Networking Information...");
await tx.wait();
// await tx.wait();
setReset(true);
setDirect(direct);
@ -82,13 +78,11 @@ function ResetNode({
}
},
[
provider,
knsName,
setReset,
setDirect,
navigate,
openConnect,
kns,
direct,
setNetworkingKey,
setIpAddress,
@ -102,14 +96,7 @@ function ResetNode({
return (
<>
<KinodeHeader header={<h1 className="flex c mb-8">
Reset Kinode Name
</h1>}
openConnect={openConnect}
closeConnect={closeConnect}
nodeChainId={nodeChainId}
/>
{Boolean(provider) ? (
{Boolean(address) ? (
<form
id="signup-form"
className="flex flex-col"

View File

@ -1,17 +1,16 @@
import React, { useState, useEffect, FormEvent, useCallback } from "react";
import KinodeHeader from "../components/KnsHeader";
import Loader from "../components/Loader";
import { utils, providers } from "ethers";
import { downloadKeyfile } from "../utils/download-keyfile";
import { Tooltip } from "../components/Tooltip";
import { KinodeTitle } from "../components/KinodeTitle";
// import { KinodeTitle } from "../components/KinodeTitle";
import { getFetchUrl } from "../utils/fetch";
import { sha256, toBytes } from "viem";
type SetPasswordProps = {
direct: boolean;
pw: string;
reset: boolean;
provider?: providers.Web3Provider,
knsName: string;
setPw: React.Dispatch<React.SetStateAction<string>>;
appSizeOnLoad: number;
@ -24,11 +23,8 @@ function SetPassword({
direct,
pw,
reset,
provider,
setPw,
appSizeOnLoad,
closeConnect,
nodeChainId,
}: SetPasswordProps) {
const [pw2, setPw2] = useState("");
const [error, setError] = useState("");
@ -53,22 +49,21 @@ function SetPassword({
setTimeout(async () => {
setLoading(true);
let hashed_password = utils.sha256(utils.toUtf8Bytes(pw));
let signer = await provider?.getSigner();
let owner = await signer?.getAddress();
let chain_id = await signer?.getChainId();
let timestamp = Date.now();
let hashed_password = sha256(toBytes(pw));
// let owner = await signer?.getAddress();
// let chain_id = await signer?.getChainId();
// let timestamp = Date.now();
let sig_data = JSON.stringify({
username: knsName,
password_hash: hashed_password,
timestamp,
direct,
reset,
chain_id,
});
// let sig_data = JSON.stringify({
// username: knsName,
// password_hash: hashed_password,
// timestamp,
// direct,
// reset,
// chain_id,
// });
let signature = await signer?.signMessage(utils.toUtf8Bytes(sig_data));
// let signature = await signer?.signMessage(utils.toUtf8Bytes(sig_data));
try {
const result = await fetch(getFetchUrl("/boot"), {
@ -80,10 +75,10 @@ function SetPassword({
reset,
username: knsName,
direct,
owner,
timestamp,
signature,
chain_id,
// owner,
// timestamp,
// signature,
// chain_id,
}),
});
const base64String = await result.json();
@ -113,12 +108,7 @@ function SetPassword({
return (
<>
<KinodeHeader
header={<KinodeTitle prefix="Set Password" showLogo />}
openConnect={() => { }}
closeConnect={closeConnect}
nodeChainId={nodeChainId}
/>
{loading ? (
<Loader msg="Setting up node..." />
) : (

View File

@ -1,8 +1,6 @@
import { SEPOLIA_OPT_HEX, OPTIMISM_OPT_HEX, MAINNET_OPT_HEX } from "../constants/chainId";
import { NetworkingInfo } from "../lib/types";
import { ipToNumber } from "./ipToNumber";
import { KNSRegistryResolver } from "../abis/types";
import { namehash } from "@ethersproject/hash";
const CHAIN_NOT_FOUND = "4902"
export interface Chain {
@ -114,7 +112,7 @@ export const generateNetworkingKeys = async ({
setRouters,
}: {
direct: boolean,
kns: KNSRegistryResolver,
kns: string,
nodeChainId: string,
chainName: string,
nameToSet: string,
@ -145,40 +143,40 @@ export const generateNetworkingKeys = async ({
setTcpPort(tcp_port || 0);
setRouters(allowed_routers);
const data = [
direct
? (
await kns.populateTransaction.setAllIp(
nameToSet,
ipAddress,
ws_port || 0, // ws
0, // wt
tcp_port || 0, // tcp
0 // udp
)
).data!
: (
await kns.populateTransaction.setRouters(
nameToSet,
allowed_routers.map((x) => namehash(x))
)
).data!,
(
await kns.populateTransaction.setKey(
nameToSet,
networking_key
)
).data!,
];
// const data = [
// direct
// ? (
// await kns.populateTransaction.setAllIp(
// nameToSet,
// ipAddress,
// ws_port || 0, // ws
// 0, // wt
// tcp_port || 0, // tcp
// 0 // udp
// )
// ).data!
// : (
// await kns.populateTransaction.setRouters(
// nameToSet,
// allowed_routers.map((x) => namehash(x))
// )
// ).data!,
// (
// await kns.populateTransaction.setKey(
// nameToSet,
// networking_key
// )
// ).data!,
// ];
try {
await setChain(nodeChainId);
} catch (error) {
window.alert(
`You must connect to the ${chainName} network to continue. Please connect and try again.`
);
throw new Error(`${chainName} not set`);
}
// try {
// await setChain(nodeChainId);
// } catch (error) {
// window.alert(
// `You must connect to the ${chainName} network to continue. Please connect and try again.`
// );
// throw new Error(`${chainName} not set`);
// }
return data
return []
}

File diff suppressed because it is too large Load Diff