Skip to content

Commit

Permalink
rework finalizing step
Browse files Browse the repository at this point in the history
  • Loading branch information
holic committed Apr 28, 2024
1 parent 6f3f62d commit d9672df
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 117 deletions.
3 changes: 1 addition & 2 deletions packages/account-kit/src/AccountModalSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ export function AccountModalSidebar() {
<Logo className="bg-neutral-100 dark:bg-transparent" />
</div>
{steps.map((step) => {
// TODO: make this less weird/janky
if (step.id === "finalizing" && (step.isComplete || !step.canComplete)) {
if (step.id === "finalizing") {
return null;
}
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { resourceToHex } from "@latticexyz/common";
import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json";
import { Account, Chain, Client, Hex, Transport, encodeFunctionData } from "viem";
import { writeContract } from "viem/actions";
import { unlimitedDelegationControlId } from "../../common";
import CallWithSignatureAbi from "@latticexyz/world-modules/out/IUnstable_CallWithSignatureSystem.sol/IUnstable_CallWithSignatureSystem.abi.json";
import { getAction } from "viem/utils";

export async function registerDelegationWithSignature({
worldAddress,
appAccountClient,
userAddress,
signature,
}: {
worldAddress: Hex;
appAccountClient: Client<Transport, Chain, Account>;
userAddress: Hex;
signature: Hex;
}) {
console.log("calling registerDelegation");
return await getAction(
appAccountClient,
writeContract,
"writeContract",
)({
address: worldAddress,
abi: CallWithSignatureAbi,
functionName: "callWithSignature",
account: appAccountClient.account,
chain: appAccountClient.chain,
args: [
userAddress,
resourceToHex({ type: "system", namespace: "", name: "Registration" }),
encodeFunctionData({
abi: IBaseWorldAbi,
functionName: "registerDelegation",
args: [appAccountClient.account.address, unlimitedDelegationControlId, "0x"],
}),
signature,
],
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useCallWithSignatureNonce } from "../../useCallWithSignatureNonce";
import { createStore } from "zustand/vanilla";
import { useMemo } from "react";
import { useStore } from "zustand";
// import { useOnboardingSteps } from "../../useOnboardingSteps";

const store = createStore(() => ({ signature: undefined as Hex | undefined }));

Expand All @@ -22,6 +23,8 @@ export function useSignRegisterDelegation() {
const { data: appAccountClient } = useAppAccountClient();
const { nonce } = useCallWithSignatureNonce();
const registerDelegationSignature = useStore(store, (state) => state.signature);
// TODO: this causes an infinite loop
// const { resetStep } = useOnboardingSteps();

const result = useMutation({
mutationFn: async () => {
Expand All @@ -43,9 +46,9 @@ export function useSignRegisterDelegation() {
nonce,
});

await queryClient.invalidateQueries();
queryClient.invalidateQueries();
store.setState({ signature });
// TODO: reset step?
// resetStep();

return signature;
},
Expand All @@ -57,6 +60,7 @@ export function useSignRegisterDelegation() {
signRegisterDelegation: result.mutate,
signRegisterDelegationAsync: result.mutateAsync,
registerDelegationSignature,
clearSignature: () => store.setState({ signature: undefined }),
}),
[registerDelegationSignature, result],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export function DepositViaTransferForm(props: Props) {
// This shouldn't happen because the submit button is marked pending while this is missing.
if (!prepared.data) throw new Error("Deposit transaction was not prepared.");

console.log("sending deposit", prepared.data);
await sendTransaction.sendTransactionAsync({
...prepared.data,
// TS complains about the `to` type, even though it ran through `usePrepareTransactionRequest`
Expand Down
173 changes: 61 additions & 112 deletions packages/account-kit/src/steps/finalizing/FinalizingStep.tsx
Original file line number Diff line number Diff line change
@@ -1,136 +1,85 @@
import { useEffect } from "react";
import { AccountModalSection } from "../../AccountModalSection";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { PendingIcon } from "../../icons/PendingIcon";
import { useSignRegisterDelegation } from "../app-account/useSignRegisterDelegation";
import { resourceToHex } from "@latticexyz/common";
import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json";
import { encodeFunctionData } from "viem";
import { writeContract } from "viem/actions";
import { usePublicClient, useWaitForTransactionReceipt, useWalletClient } from "wagmi";
import { unlimitedDelegationControlId } from "../../common";
import { useAccount } from "wagmi";
import { useAppAccountClient } from "../../useAppAccountClient";
import { useOnboardingSteps } from "../../useOnboardingSteps";
import { useConfig } from "../../AccountKitConfigProvider";
import CallWithSignatureAbi from "@latticexyz/world-modules/out/IUnstable_CallWithSignatureSystem.sol/IUnstable_CallWithSignatureSystem.abi.json";
import { getAction } from "viem/utils";
import { useAppChain } from "../../useAppChain";
import { registerDelegationWithSignature } from "../app-account/registerDelegationWithSignature";
import { waitForTransactionReceipt } from "viem/actions";
import { useAccountModal } from "../../useAccountModal";

export function FinalizingStep() {
const queryClient = useQueryClient();
const { worldAddress } = useConfig();
const chain = useAppChain();
const publicClient = usePublicClient({ chainId: chain.id });
const { data: userAccountClient } = useWalletClient({ chainId: chain.id });
const { data: appAccountClient } = useAppAccountClient();
const { address: userAddress } = useAccount();
const { resetStep } = useOnboardingSteps();
const { registerDelegationSignature } = useSignRegisterDelegation();
const { registerDelegationSignature, clearSignature } = useSignRegisterDelegation();
const { closeAccountModal } = useAccountModal();

// We `writeContract` in a mutation here so we can control the client.
// If we used wagmi's `useWriteContract`, it would write with the connected account instead, which is not what we want.

const canRegisterDelegation = !!(
publicClient?.uid &&
userAccountClient?.uid &&
appAccountClient?.uid &&
registerDelegationSignature
);
const mutationKey = [
// I am taking a bit of a gamble here executing a transaction with useQuery,
// but I couldn't get useMutation to play nicely without sending the transaction
// multiple times. I could track when the mutation was called, but that's kinda
// what useQuery is meant to do for us with queryKey.
const queryKey = [
"registerDelegation",
publicClient?.uid,
userAccountClient?.uid,
appAccountClient?.uid,
worldAddress,
appAccountClient?.chain.id.toString(),
appAccountClient?.account.address,
userAddress,
registerDelegationSignature,
];
console.log("mutation key", mutationKey);
const registerDelegation = useMutation({
mutationKey,
mutationFn: async () => {
if (!publicClient) throw new Error("Public client not ready. Not connected?");
if (!userAccountClient) throw new Error("Wallet client not ready. Not connected?");
if (!appAccountClient) throw new Error("App account client not ready.");
if (!registerDelegationSignature) throw new Error("No delegation signature.");

console.log("calling registerDelegation");
return await getAction(
appAccountClient,
writeContract,
"writeContract",
)({
address: worldAddress,
abi: CallWithSignatureAbi,
functionName: "callWithSignature",
account: appAccountClient.account,
chain,
args: [
userAccountClient.account.address,
resourceToHex({ type: "system", namespace: "", name: "Registration" }),
encodeFunctionData({
abi: IBaseWorldAbi,
functionName: "registerDelegation",
args: [appAccountClient.account.address, unlimitedDelegationControlId, "0x"],
}),
registerDelegationSignature,
],
});

// console.log("registerDelegation tx", delegationHash);

// const receipt = await waitForTransactionReceipt(publicClient, {
// hash: delegationHash,
// pollingInterval: defaultPollingInterval,
// retryCount: 10,
// });
// console.log("registerDelegation receipt", receipt);
// if (receipt.status === "reverted") {
// console.error("Failed to register delegation.", receipt);
// throw new Error("Failed to register delegation.");
// }

// queryClient.invalidateQueries();
// resetStep();
},
});

const receipt = useWaitForTransactionReceipt({
chainId: chain.id,
hash: registerDelegation.data,
pollingInterval: 1_000,
});

useEffect(() => {
if (receipt.data?.status === "success") {
queryClient.invalidateQueries();
resetStep();
}
}, [queryClient, receipt.data, resetStep]);

useEffect(() => {
if (canRegisterDelegation && registerDelegation.isIdle) {
registerDelegation.mutateAsync();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [canRegisterDelegation, registerDelegation.isIdle]);

if (registerDelegation.error) {
// TODO: make this prettier
return <AccountModalSection>{String(registerDelegation.error)}</AccountModalSection>;
}
if (receipt.error) {
// TODO: make this prettier
return <AccountModalSection>{String(receipt.error)}</AccountModalSection>;
}
const registerDelegation = useQuery(
worldAddress && appAccountClient && userAddress && registerDelegationSignature
? {
queryKey,
queryFn: async () => {
console.log("calling registerDelegationWithSignature");
const hash = await registerDelegationWithSignature({
worldAddress,
appAccountClient,
userAddress,
signature: registerDelegationSignature,
});
console.log("waiting for delegation tx", hash);
const receipt = await waitForTransactionReceipt(appAccountClient, { hash });
console.log("got delegation receipt", receipt);
console.log("clearing query cache");
queryClient.invalidateQueries();
clearSignature();
resetStep();
closeAccountModal();
return receipt;
},
refetchOnMount: false,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
retry: false,
}
: {
queryKey,
enabled: false,
},
);

if (receipt.isPending) {
// TODO: make this prettier
if (registerDelegation.isError) {
console.error("register delegation error", registerDelegation.error);
return (
<AccountModalSection className="flew-grow">
<div className="grid place-items-center">
receipt: {receipt.data} <PendingIcon />
</div>
<AccountModalSection>
{/* TODO nicer error */}
<div className="p-5 whitespace-break-spaces">{String(registerDelegation.error)}</div>
</AccountModalSection>
);
}

return <></>;
return (
<AccountModalSection className="flex-grow">
<div className="flex-grow flex flex-col items-center justify-center">
<PendingIcon />
</div>
</AccountModalSection>
);
}
2 changes: 1 addition & 1 deletion packages/account-kit/src/useENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function useENS(address: Hex | undefined) {
avatar: string | undefined;
}>({
enabled: !!normalizedAddress,
queryKey: [normalizedAddress],
queryKey: ["ens", normalizedAddress],
initialData: {
address: undefined,
name: undefined,
Expand Down

0 comments on commit d9672df

Please sign in to comment.