Skip to content

Commit

Permalink
Companion app fund arcade account (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
fracek committed May 29, 2024
2 parents 8f1f74e + 7a89727 commit 9d71e87
Show file tree
Hide file tree
Showing 14 changed files with 5,816 additions and 26 deletions.
5,169 changes: 5,169 additions & 0 deletions demos/companion-app/package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion demos/companion-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
"lint": "next lint"
},
"dependencies": {
"@hookform/resolvers": "^3.3.2",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
"@starknet-react/chains": "^0.1.0",
"@starknet-react/core": "^2.0.0",
Expand All @@ -22,9 +25,11 @@
"next": "14.0.2",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.49.2",
"starknet": "^5.19.5",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/node": "^20",
Expand Down
11 changes: 1 addition & 10 deletions demos/companion-app/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import WalletBar from "@/components/wallet-bar";

export default function Home() {
return (
<main className="flex flex-col items-center justify-center min-h-screen gap-12">
<WalletBar />
<p className="mb-2 text-lg">
Get started by editing&nbsp;
<code className="p-2 bg-gray-600 rounded">app/pages.tsx</code>
</p>

</main>
);
return <div>Home</div>;
}
31 changes: 24 additions & 7 deletions demos/companion-app/src/app/setup/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import WalletBar from '@/components/wallet-bar';
import { ConnectModal } from "@/components/connect-modal";
import { FundArcadeAccount } from "@/components/fund-arcade-account";

const Setup = () => {
interface Props {
searchParams: { [key: string]: string };
}

const Setup = ({ searchParams }: Props) => {
const publicKey = searchParams["pk"];

if (!publicKey) {
return (
<div className="text-2xl w-full justify-center mx-auto my-0 items-center text-center p-2 bg-red-500">
Invalid url
</div>
);
}
return (
<div>
Setup Account
</div>
<main className="flex flex-col items-center justify-center min-h-screen ">
<div className="w-full h-[500px] max-w-[500px] rounded-md bg-slate-400 gap-[30px] flex justify-center items-center flex-col">
<ConnectModal />
<FundArcadeAccount pk={publicKey} />
</div>
</main>
);
}
};

export default Setup;
export default Setup;
63 changes: 63 additions & 0 deletions demos/companion-app/src/components/connect-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"use client";

import { useConnect, Connector, useAccount } from "@starknet-react/core";
import { Dialog, DialogHeader } from "./ui/dialog";
import { Button } from "./ui/button";
import {
DialogClose,
DialogContent,
DialogOverlay,
DialogPortal,
DialogTitle,
DialogTrigger,
} from "@radix-ui/react-dialog";
import { useState } from "react";
import { WalletConnected } from "./wallet-bar";

export const ConnectModal = () => {
const { connect, connectors } = useConnect();
const [open, setOpen] = useState(false);
const { address } = useAccount();

const handleConnect = (connector: Connector) => {
connect({ connector });
setOpen(false);
};

return (
<Dialog open={open} onOpenChange={setOpen}>
{!open && !address && (
<DialogTrigger className="hover:bg-purple px-6 py-3 rounded-lg hover:text-white">
Connect Wallet
</DialogTrigger>
)}
{address && <WalletConnected />}
<DialogPortal>
<DialogOverlay className="fixed inset-0 bg-black/40" />
<DialogContent className="bg-black/30 fixed left-1/2 top-1/2 z-30 rounded-lg p-4 -translate-x-1/2 -translate-y-1/2">
<DialogHeader className="px-2 pb-2 flex flex-row items-center justify-between">
<DialogTitle>Connect Wallet</DialogTitle>
<DialogClose>X</DialogClose>
</DialogHeader>
<div className="flex flex-col gap-2">
{connectors.map((connector: Connector) => {
return (
<Button
key={connector.id}
onClick={async () => handleConnect(connector)}
disabled={!connector.available()}
className="flex flex-row items-center justify-start gap-4 w-96"
>
{connector.icon.light && (
<img src={connector.icon.dark} className="w-10 h-10" />
)}
<p className="">Connect {connector.name}</p>
</Button>
);
})}
</div>
</DialogContent>
</DialogPortal>
</Dialog>
);
};
145 changes: 145 additions & 0 deletions demos/companion-app/src/components/fund-arcade-account.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"use client";
import {
useAccount,
useContractWrite,
useContractRead,
useNetwork,
} from "@starknet-react/core";

import { useMemo, useState } from "react";
import { CallData, stark, uint256 } from "starknet";
import { z } from "zod";
import { abi } from "@/lib/factory";
import { Input } from "./ui/input";
import { useForm } from "react-hook-form";
import { Label } from "./ui/label";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "./ui/button";
import { Card, CardContent } from "./ui/card";
import { bnToHex } from "@/lib/utils";
import { deployerAddress } from "@/lib/constants";

interface Props {
pk: string;
}

const schema = z.object({
initialSupply: z.number().min(0),
});
export const FundArcadeAccount = ({ pk }: Props) => {
const { address, account } = useAccount();
const { chain } = useNetwork();

const {
register,
handleSubmit,
formState: { errors },
reset: resetForm,
} = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
defaultValues: { initialSupply: 0.0001 },
});

const salt = useMemo(() => {
return stark.randomAddress();
}, [account]);
const { writeAsync, reset: resetWrite, error } = useContractWrite({});

const [deployedToken, setDeployedToken] = useState<
{ address: string; tx: string } | undefined
>(undefined);

const { data: arcadeAccountAddress } = useContractRead({
abi,
address: deployerAddress,
functionName: "compute_address",
args: [salt, pk, address as string],
});

const deployToken = async (data: z.infer<typeof schema>) => {
if (!address) return;

const hexAddres = bnToHex(arcadeAccountAddress as bigint);

const deploy = {
contractAddress: deployerAddress,
entrypoint: "deploy",
calldata: [salt, pk, address],
};

const transfer = {
contractAddress: chain.nativeCurrency.address,
entrypoint: "transfer",
calldata: CallData.compile([
hexAddres,
uint256.bnToUint256(
BigInt(
data.initialSupply * Math.pow(10, chain.nativeCurrency.decimals)
)
),
]),
};

try {
const res = await writeAsync({
calls: [transfer, deploy],
});
setDeployedToken({
address: hexAddres as string,
tx: res.transaction_hash,
});
} catch (err) {
console.log(err);
}
};

const restart = () => {
resetWrite();
resetForm();
setDeployedToken(undefined);
};

return (
<>
{address && (
<form onSubmit={handleSubmit(deployToken)}>
<Label className="px-[10px]">Fund amount:</Label>
<div className="flex flex-row gap-4 px-[10px]">
<Input
placeholder="0.0001"
type="number"
step="any"
{...register("initialSupply", { valueAsNumber: true })}
/>
<Button className="w-[115px]" type="submit">
Submit
</Button>

<Button type="button" onClick={restart} className="w-[115px]">
Start over
</Button>
</div>
{errors.initialSupply?.message ? (
<div className="p-2 bg-red-500 mt-[10px] text-center">
{errors.initialSupply?.message}
</div>
) : null}
</form>
)}

{deployedToken && (
<Card className="max-w-[500px] w-full bg-transparent border-none">
<CardContent className="px-[10px]">
<div className="flex text-md w-full break-all flex-col gap-2">
<div className="items-center text-xl flex text-center justify-center">
Token Deployed!
</div>
<div>Token address:</div>
<div>{deployedToken.address}</div>
</div>
</CardContent>
</Card>
)}
</>
);
};
Loading

0 comments on commit 9d71e87

Please sign in to comment.