diff --git a/ui/src/app/components/ArcadeDialog.tsx b/ui/src/app/components/ArcadeDialog.tsx index 497349e25..a4b2e2a4e 100644 --- a/ui/src/app/components/ArcadeDialog.tsx +++ b/ui/src/app/components/ArcadeDialog.tsx @@ -23,7 +23,8 @@ import ArcadeLoader from "@/app/components/animations/ArcadeLoader"; import TokenLoader from "@/app/components/animations/TokenLoader"; import TopupInput from "@/app/components/arcade/TopupInput"; import RecoverUndeployed from "@/app/components/arcade/RecoverUndeployed"; -import RecoverArcade from "@/app/components//arcade/RecoverArcade"; +import RecoverArcade from "@/app/components/arcade/RecoverArcade"; +import MigrateAA from "@/app/components/arcade/MigrateAA"; import Storage from "@/app/lib/storage"; import { BurnerStorage } from "@/app/types"; @@ -51,6 +52,7 @@ export const ArcadeDialog = ({ const [fetchedBalances, setFetchedBalances] = useState(false); const [recoverArcade, setRecoverArcade] = useState(false); const [recoverUndeployed, setRecoverUndeployed] = useState(false); + const [migrateAA, setMigrateAA] = useState(false); const [fullDeployment, setFullDeployment] = useState(false); const { account: walletAccount, address, connector } = useAccount(); const showArcadeDialog = useUIStore((state) => state.showArcadeDialog); @@ -177,6 +179,17 @@ export const ArcadeDialog = ({ walletAccount={walletAccount!} updateConnectors={updateConnectors} /> + ) : migrateAA ? ( + ) : ( <>
@@ -216,6 +229,9 @@ export const ArcadeDialog = ({ +
@@ -463,7 +479,7 @@ export const ArcadeAccountCard = ({ /> )} -
+
- {masterAccountAddress == walletAccount?.address && ( - <> - - - - )} {connected && (
+ {masterAccountAddress == walletAccount?.address && ( +
+ + +
+ )}
); diff --git a/ui/src/app/components/arcade/MigrateAA.tsx b/ui/src/app/components/arcade/MigrateAA.tsx new file mode 100644 index 000000000..aca41a2b5 --- /dev/null +++ b/ui/src/app/components/arcade/MigrateAA.tsx @@ -0,0 +1,182 @@ +import { ChangeEvent, useState, useEffect } from "react"; +import { AccountInterface, CallData, Contract, ec, hash } from "starknet"; +import { Connector, useContract } from "@starknet-react/core"; +import { padAddress, isChecksumAddress } from "@/app/lib/utils"; +import { Button } from "@/app/components/buttons/Button"; +import Storage from "@/app/lib/storage"; +import ArcadeAccount from "@/app/abi/ArcadeAccount.json"; + +interface MigrateAAProps { + setMigrateAA: (migrateAA: boolean) => void; + walletAccount: AccountInterface; + walletConnectors: Connector[]; + connector: Connector; + gameContract: Contract; + connect: any; + disconnect: any; + updateConnectors: () => void; +} + +const MigrateAA = ({ + setMigrateAA, + walletAccount, + walletConnectors, + connector, + gameContract, + connect, + disconnect, + updateConnectors, +}: MigrateAAProps) => { + const [arcadePrivateKey, setArcadePrivateKey] = useState< + string | undefined + >(); + const [arcadeExists, setArcadeExists] = useState(false); + const [arcadeAddress, setArcadeAddress] = useState(); + const [arcadePublicKey, setArcadePublicKey] = useState(); + const [masterAccount, setMasterAccount] = useState(); + + const formattedArcadeAddress = padAddress(padAddress(arcadeAddress ?? "")); + + const storage = Storage.get("burners") || {}; + + const handleChange = ( + e: ChangeEvent + ) => { + const { value } = e.target; + setArcadePrivateKey(value); + }; + + const { contract: arcadeContract } = useContract({ + address: formattedArcadeAddress, + abi: ArcadeAccount, + }); + + const getMasterAccount = async () => { + try { + const masterAccount = await arcadeContract?.call("get_master_account"); + if (masterAccount) { + setArcadeExists(true); + setMasterAccount("0x" + masterAccount?.toString(16)); + } + } catch (e) { + console.log(e); + } + }; + + const handleGetArcade = () => { + if (isChecksumAddress(arcadePrivateKey!)) { + const publicKey = ec.starkCurve.getStarkKey(arcadePrivateKey!); + + if (!walletAccount) { + throw new Error("wallet account not found"); + } + + const constructorAACalldata = CallData.compile({ + _public_key: publicKey, + _master_account: walletAccount.address, + }); + + const address = hash.calculateContractAddressFromHash( + publicKey, + process.env.NEXT_PUBLIC_ARCADE_ACCOUNT_CLASS_HASH!, + constructorAACalldata, + 0 + ); + + setArcadeAddress(address); + setArcadePublicKey(publicKey); + } + }; + + const importBurner = () => { + storage[formattedArcadeAddress!] = { + privateKey: arcadePrivateKey, + publicKey: arcadePublicKey, + masterAccount: walletAccount.address, + masterAccountProvider: connector.id, + gameContract: gameContract?.address, + active: true, + }; + + Storage.set("burners", storage); + }; + + const arcadeAccountExists = () => { + if (storage) { + return Object.keys(storage).includes(formattedArcadeAddress ?? ""); + } else { + return false; + } + }; + + const isMasterAccount = + padAddress(walletAccount.address) === padAddress(masterAccount ?? ""); + + useEffect(() => { + if (arcadePrivateKey) { + handleGetArcade(); + } + }, [arcadePrivateKey]); + + useEffect(() => { + if (arcadeAddress) { + getMasterAccount(); + } + }, [arcadeAddress]); + + return ( +
+

Import Arcade Account

+

+ Please enter the private key of the Arcade Account you would like to + import to this client. +

+ + {!isMasterAccount && arcadeAddress && ( + <> +

Connect Master Account

+ {walletConnectors.map((connector, index) => ( + + ))} + + )} + +
+ ); +}; + +export default MigrateAA;