Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions hyperdrive/src/register-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Navigate, BrowserRouter as Router, Route, Routes, useParams } from 'rea
import CommitDotOsName from "./pages/CommitDotOsName";
import MintDotOsName from "./pages/MintDotOsName";
import MintCustom from "./pages/MintCustom";
import UpgradeCustom from "./pages/UpgradeCustom";
import SetPassword from "./pages/SetPassword";
import Login from './pages/Login'
import ResetName from './pages/ResetName'
Expand All @@ -24,6 +25,8 @@ function App() {
const [reset, setReset] = useState<boolean>(false);
const [direct, setDirect] = useState<boolean>(false);
const [hnsName, setHnsName] = useState<string>('');
const [tbaAddress, setTbaAddress] = useState<string>('');
const [implAddress, setImplAddress] = useState<string>('');
const [networkingKey, setNetworkingKey] = useState<string>('');
const [ipAddress, setIpAddress] = useState<number>(0);
const [ws_port, setWsPort] = useState<number>(0);
Expand Down Expand Up @@ -94,6 +97,10 @@ function App() {
tcp_port, setTcpPort,
routers, setRouters,
nodeChainId,
tbaAddress,
setTbaAddress,
implAddress,
setImplAddress
}

return (
Expand Down Expand Up @@ -138,6 +145,12 @@ function App() {
<MintCustom {...props} />
</>
} />

<Route path="/custom-upgrade" element={
<>
<UpgradeCustom {...props} />
</>
} />
</Routes>
</main>
</Router>
Expand Down
4 changes: 4 additions & 0 deletions hyperdrive/src/register-ui/src/abis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ export const dotOsAbi = parseAbi([
export const tbaMintAbi = parseAbi([
"function mint(address who, bytes calldata name, bytes calldata initialization, address implementation) external returns (address)"
]);

export const tbaUpgradeAbi = parseAbi([
"function upgradeToAndCall(address newImpl, bytes calldata data) external"
]);
2 changes: 1 addition & 1 deletion hyperdrive/src/register-ui/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface PageProps {
setReset: React.Dispatch<React.SetStateAction<boolean>>,
pw: string,
setPw: React.Dispatch<React.SetStateAction<string>>,
nodeChainId: string,
nodeChainId: string
}

export type NetworkingInfo = {
Expand Down
4 changes: 4 additions & 0 deletions hyperdrive/src/register-ui/src/pages/HyperdriveHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function HyperdriveHome({ hnsName }: OsHomeProps) {
const importKeyfileRedir = () => navigate('/import-keyfile')
const loginRedir = () => navigate('/login')
const customRegisterRedir = () => navigate('/custom-register')
const customUpgradeRedir = () => navigate('/custom-upgrade')
const previouslyBooted = Boolean(hnsName)

useEffect(() => {
Expand Down Expand Up @@ -49,6 +50,9 @@ function HyperdriveHome({ hnsName }: OsHomeProps) {
<button onClick={customRegisterRedir} className="button secondary">
Register Non-.os Name (Advanced)
</button>
<button onClick={customUpgradeRedir} className="button secondary">
Upgrade Hyper Account (Advanced)
</button>
</div>
</>
)}
Expand Down
179 changes: 179 additions & 0 deletions hyperdrive/src/register-ui/src/pages/UpgradeCustom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { useState, useEffect, FormEvent, useCallback } from "react";
import Loader from "../components/Loader";
import { PageProps } from "../lib/types";
import { useAccount, useWaitForTransactionReceipt, useSendTransaction } from "wagmi";
import { useConnectModal, useAddRecentTransaction } from "@rainbow-me/rainbowkit";
import { tbaUpgradeAbi } from "../abis";
import { encodeFunctionData, stringToHex } from "viem";
import BackButton from "../components/BackButton";

interface UpgradeCustomNameProps extends PageProps { }

function UpgradeCustom({ }: UpgradeCustomNameProps) {
const { address } = useAccount();
const { openConnectModal } = useConnectModal();

const [tbaAddress, setTbaAddress] = useState<string>("");
const [implAddress, setImplAddress] = useState<string>("");
const [showSuccess, setShowSuccess] = useState<boolean>(false);

const { data: hash, sendTransaction, isPending, isError, error } = useSendTransaction({
mutation: {
onSuccess: (data) => {
addRecentTransaction({ hash: data, description: `Upgrade implementation` });
},
},
});

const { isLoading: isConfirming, isSuccess: isConfirmed } =
useWaitForTransactionReceipt({ hash });

const addRecentTransaction = useAddRecentTransaction();

useEffect(() => {
document.title = "Upgrade Hyper Account";
}, []);

useEffect(() => {
if (!address) {
openConnectModal?.();
}
}, [address, openConnectModal]);

const handleUpgrade = useCallback(
async (e: FormEvent) => {
e.preventDefault();
e.stopPropagation();

if (!address) {
openConnectModal?.();
return;
}

const tba = tbaAddress as `0x${string}`;
const impl = implAddress as `0x${string}`;

const data = encodeFunctionData({
abi: tbaUpgradeAbi,
functionName: "upgradeToAndCall",
args: [impl, stringToHex("")],
});

try {
sendTransaction({
to: tba,
data,
gas: 1000000n,
});
} catch (error) {
console.error("Failed to send transaction:", error);
}
},
[address, sendTransaction, openConnectModal, tbaAddress, implAddress],
);

const isFormValid = tbaAddress.trim() !== "" && implAddress.trim() !== "";

// show success screen and reset form on confirmation
useEffect(() => {
if (isConfirmed) {
setTbaAddress("");
setImplAddress("");
setShowSuccess(true);
}
}, [isConfirmed]);

const handleUpgradeNew = () => {
setShowSuccess(false);
};

return (
<div className="container fade-in">
<div className="section">
<form className="form" onSubmit={handleUpgrade}>
{isPending || isConfirming ? (
<Loader msg={isConfirming ? "Upgrading..." : "Please confirm the transaction in your wallet"} />
) : showSuccess ? (
<>
<p className="form-label">
<span>✅ Upgrade Successful!</span>
</p>
<p className="text-center mb-4">
Your Hyper Account has been successfully upgraded.
</p>
<div className="flex flex-col gap-1">
<button
type="button"
className="button"
onClick={handleUpgradeNew}
>
Upgrade New
</button>
<BackButton mode="wide" />
</div>
</>
) : (
<>
<p className="form-label">
<span>Upgrade Hyper Account Implementation</span>
</p>

<div className="mb-4 text-sm text-gray-300 space-y-2">
<p>
<strong>What is "Upgrade Hyper Account"?</strong>
</p>
<p>
When minting a Hyper Account, you can make it upgradable. This allows the operator
to update the contract implementation and add or remove various functions without
changing the account address.
</p>
<p>
This page allows you to upgrade an existing upgradable Hyper Account (TBA - Token Bound Account)
to a new implementation contract. The new implementation can include additional features,
bug fixes, or optimizations.
</p>
<p className="text-yellow-400">
⚠️ In the default implementation, only the operator can call upgradeToAndCall.
This operation requires ERC-1967 support in both the account and implementation contracts.
</p>
</div>

<input
type="text"
name="tba"
placeholder="Enter TBA address to upgrade"
value={tbaAddress}
onChange={(e) => setTbaAddress(e.target.value)}
/>
<input
type="text"
name="impl"
placeholder="Enter new implementation address"
value={implAddress}
onChange={(e) => setImplAddress(e.target.value)}
/>

<div className="flex flex-col gap-1">
<button
type="submit"
className="button"
disabled={!isFormValid || isPending || isConfirming}
>
Upgrade Hyper Account
</button>
<BackButton mode="wide" />
</div>
</>
)}
{isError && !showSuccess && (
<p className="text-red-500 wrap-anywhere mt-2">
Error: {error?.message || "There was an error on upgrade"}
</p>
)}
</form>
</div>
</div>
);
}

export default UpgradeCustom;
2 changes: 2 additions & 0 deletions hyperdrive/src/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub async fn register(
.or(warp::path("import-keyfile"))
.or(warp::path("set-password"))
.or(warp::path("custom-register"))
.or(warp::path("custom-upgrade"))
.and(warp::get())
.map(move |_| warp::reply::html(include_str!("register-ui/build/index.html")));
#[cfg(target_os = "windows")]
Expand All @@ -127,6 +128,7 @@ pub async fn register(
.or(warp::path("import-keyfile"))
.or(warp::path("set-password"))
.or(warp::path("custom-register"))
.or(warp::path("custom-upgrade"))
.and(warp::get())
.map(move |_| warp::reply::html(include_str!("register-ui\\build\\index.html")));

Expand Down