Skip to content

Commit

Permalink
Implement AA Migration Tools (#541)
Browse files Browse the repository at this point in the history
* - implement new import AA screen
- implement export private key button on arcade accounts

* - finish check if arcade already stored

* - fix overflow scrolling

* clean
  • Loading branch information
starknetdev authored Jan 25, 2024
1 parent 5f72304 commit 79ffc89
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 21 deletions.
66 changes: 45 additions & 21 deletions ui/src/app/components/ArcadeDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -177,6 +179,17 @@ export const ArcadeDialog = ({
walletAccount={walletAccount!}
updateConnectors={updateConnectors}
/>
) : migrateAA ? (
<MigrateAA
setMigrateAA={setMigrateAA}
walletAccount={walletAccount!}
walletConnectors={walletConnectors}
connector={connector!}
gameContract={gameContract}
connect={connect}
disconnect={disconnect}
updateConnectors={updateConnectors}
/>
) : (
<>
<div className="flex flex-col">
Expand Down Expand Up @@ -216,6 +229,9 @@ export const ArcadeDialog = ({
<Button onClick={() => setRecoverUndeployed(true)}>
Recover Undeployed
</Button>
<Button onClick={() => setMigrateAA(true)}>
Import Arcade
</Button>
</div>
</div>
</div>
Expand Down Expand Up @@ -463,7 +479,7 @@ export const ArcadeAccountCard = ({
/>
)}
</div>
<div className="flex flex-col gap-2 items-center">
<div className="flex flex-col sm:gap-2 items-center">
<div className="flex">
<Button
variant={"ghost"}
Expand All @@ -477,25 +493,6 @@ export const ArcadeAccountCard = ({
>
{connected ? "Connect to Master" : "Connect"}
</Button>
{masterAccountAddress == walletAccount?.address && (
<>
<Button
variant={"ghost"}
onClick={async () => await genNewKey(account.name, connector!)}
>
Create New Keys
</Button>
<Button
variant={"ghost"}
onClick={async () => {
await setPermissions(account.name, walletAccount, true);
}}
className={`${currentGamePermissions ? "" : "animate-pulse"}`}
>
Set Permissions
</Button>
</>
)}
{connected && (
<Button
variant={"ghost"}
Expand All @@ -514,7 +511,34 @@ export const ArcadeAccountCard = ({
Withdraw To Master
</Button>
)}
<Button
variant={"ghost"}
onClick={() => {
copyToClipboard(storage[account.name].privateKey);
}}
>
Export PK
</Button>
</div>
{masterAccountAddress == walletAccount?.address && (
<div className="flex">
<Button
variant={"ghost"}
onClick={async () => await genNewKey(account.name, connector!)}
>
Create New Keys
</Button>
<Button
variant={"ghost"}
onClick={async () => {
await setPermissions(account.name, walletAccount, true);
}}
className={`${currentGamePermissions ? "" : "animate-pulse"}`}
>
Set Permissions
</Button>
</div>
)}
</div>
</div>
);
Expand Down
182 changes: 182 additions & 0 deletions ui/src/app/components/arcade/MigrateAA.tsx
Original file line number Diff line number Diff line change
@@ -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<boolean>(false);
const [arcadeAddress, setArcadeAddress] = useState<string | undefined>();
const [arcadePublicKey, setArcadePublicKey] = useState<string | undefined>();
const [masterAccount, setMasterAccount] = useState<string | undefined>();

const formattedArcadeAddress = padAddress(padAddress(arcadeAddress ?? ""));

const storage = Storage.get("burners") || {};

const handleChange = (
e: ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => {
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 (
<div className="flex flex-col items-center gap-5 h-3/4 w-full overflow-scroll">
<p className="text-2xl uppercase">Import Arcade Account</p>
<p className="text-lg">
Please enter the private key of the Arcade Account you would like to
import to this client.
</p>
<input
type="text"
name="address"
onChange={handleChange}
className="p-1 m-2 bg-terminal-black border border-terminal-green animate-pulse transform w-1/2 2xl:h-16 2xl:text-4xl"
maxLength={66}
/>
{!isMasterAccount && arcadeAddress && (
<>
<p className="text-lg">Connect Master Account</p>
{walletConnectors.map((connector, index) => (
<Button
onClick={() => {
disconnect();
connect({ connector });
}}
key={index}
>
{connector.id === "braavos" || connector.id === "argentX"
? `Connect ${connector.id}`
: "Login With Email"}
</Button>
))}
</>
)}
<Button
disabled={
!isChecksumAddress(arcadePrivateKey!) ||
!arcadeExists ||
arcadeAccountExists()
}
onClick={() => {
importBurner();
updateConnectors();
setMigrateAA(false);
}}
className="w-1/4"
>
{!arcadeExists
? "Arcade Doesn't Exist"
: arcadeAccountExists()
? "Arcade Already Stored"
: "Import Arcade"}
</Button>
</div>
);
};

export default MigrateAA;

1 comment on commit 79ffc89

@vercel
Copy link

@vercel vercel bot commented on 79ffc89 Jan 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.