Skip to content

Commit 5ebd3d3

Browse files
authored
fix(entrykit): move session account creation, use balance instead of allowance step (#3799)
1 parent 65e4592 commit 5ebd3d3

4 files changed

Lines changed: 89 additions & 103 deletions

File tree

packages/entrykit/src/onboarding/ConnectedSteps.tsx

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import { twMerge } from "tailwind-merge";
44
import { ConnectedClient } from "../common";
55
import { usePrerequisites } from "./usePrerequisites";
66
import { Wallet } from "./Wallet";
7-
import { Allowance } from "./quarry/Allowance";
87
import { Session } from "./Session";
98
import { Step } from "./common";
109
import { useAccountModal } from "../useAccountModal";
1110
import { useEntryKitConfig } from "../EntryKitConfigProvider";
1211
import { getPaymaster } from "../getPaymaster";
1312
import { GasBalance } from "./GasBalance";
14-
import { GasBalance as GasBalanceQuarry } from "./quarry/GasBalance";
13+
import { GasBalance as QuarryGasBalance } from "./quarry/GasBalance";
1514
import { Connector } from "wagmi";
1615

1716
export type Props = {
@@ -82,19 +81,11 @@ export function ConnectedSteps({ connector, userClient, initialUserAddress }: Pr
8281
});
8382
}
8483
} else if (paymaster.type === "quarry") {
85-
if (paymaster.canSponsor) {
86-
steps.push({
87-
id: "allowance",
88-
isComplete: !!hasAllowance,
89-
content: (props) => <Allowance {...props} userAddress={userAddress} />,
90-
});
91-
} else {
92-
steps.push({
93-
id: "gasBalanceQuarry",
94-
isComplete: !!hasQuarryGasBalance,
95-
content: (props) => <GasBalanceQuarry {...props} userAddress={userAddress} />,
96-
});
97-
}
84+
steps.push({
85+
id: "gasBalanceQuarry",
86+
isComplete: !!hasQuarryGasBalance || !!hasAllowance,
87+
content: (props) => <QuarryGasBalance {...props} userAddress={userAddress} paymaster={paymaster} />,
88+
});
9889
}
9990

10091
steps.push({

packages/entrykit/src/onboarding/quarry/Allowance.tsx

Lines changed: 0 additions & 61 deletions
This file was deleted.

packages/entrykit/src/onboarding/quarry/GasBalance.tsx

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,63 @@ import { ArrowLeftIcon } from "../../icons/ArrowLeftIcon";
1111
import { StepContentProps } from "../common";
1212
import { usePrevious } from "../../errors/usePrevious";
1313
import { WithdrawGasBalanceButton } from "./WithdrawGasBalanceButton";
14+
import { useAllowance } from "./useAllowance";
15+
import { useRequestAllowance } from "./useRequestAllowance";
16+
import { Paymaster } from "../../getPaymaster";
1417

1518
export type Props = StepContentProps & {
1619
userAddress: Hex;
20+
paymaster: Paymaster;
1721
};
1822

19-
export function GasBalance({ isActive, isExpanded, isFocused, setFocused, userAddress }: Props) {
23+
export function GasBalance({ isActive, isExpanded, isFocused, setFocused, userAddress, paymaster }: Props) {
2024
const queryClient = useQueryClient();
2125
const balance = useShowQueryError(useBalance(userAddress));
2226
const prevBalance = usePrevious(balance.data || 0n);
2327

28+
const allowance = useShowQueryError(useAllowance(userAddress));
29+
const prevAllowance = usePrevious(allowance.data || 0n);
30+
const requestAllowance = useRequestAllowance();
31+
2432
useEffect(() => {
2533
if (balance.data != null && prevBalance === 0n && balance.data > 0n) {
2634
queryClient.invalidateQueries({ queryKey: ["getPrerequisites"] });
2735
setFocused(false);
2836
}
2937
}, [balance.data, prevBalance, setFocused, queryClient, userAddress]);
3038

39+
useEffect(() => {
40+
if (allowance.data != null && prevAllowance === 0n && allowance.data > 0n) {
41+
queryClient.invalidateQueries({ queryKey: ["getPrerequisites"] });
42+
setFocused(false);
43+
}
44+
}, [allowance.data, prevAllowance, setFocused, queryClient, userAddress]);
45+
46+
const gasBalance = balance.data != null && allowance.data != null ? balance.data + allowance.data : null;
47+
useEffect(() => {
48+
if (!isActive) return;
49+
if (!paymaster.canSponsor) return;
50+
if (gasBalance !== 0n) return;
51+
if (requestAllowance.status !== "idle") return;
52+
53+
// There seems to be a tanstack-query bug(?) where multiple simultaneous renders loses
54+
// state between the two mutations. They're not treated as shared state but rather
55+
// individual mutations, even though the keys match. And the one we want the status of
56+
// seems to stay pending. This is sorta resolved by triggering this after a timeout.
57+
const timer = setTimeout(() => {
58+
console.log("no funds, requesting allowance");
59+
requestAllowance.mutate(userAddress, {
60+
onSuccess(data) {
61+
console.log("got allowance", data);
62+
},
63+
onError(error) {
64+
console.log("failed to get allowance", error);
65+
},
66+
});
67+
});
68+
return () => clearTimeout(timer);
69+
}, [isActive, paymaster.canSponsor, gasBalance, requestAllowance, userAddress]);
70+
3171
if (isFocused) {
3272
return (
3373
<div>
@@ -52,7 +92,7 @@ export function GasBalance({ isActive, isExpanded, isFocused, setFocused, userAd
5292
<div>
5393
<div>Gas balance</div>
5494
<div className="font-mono text-white">
55-
{balance.data != null ? <Balance wei={balance.data} /> : <PendingIcon className="text-sm" />}
95+
{gasBalance != null ? <Balance wei={gasBalance} /> : <PendingIcon className="text-sm" />}
5696
</div>
5797
</div>
5898

@@ -61,7 +101,9 @@ export function GasBalance({ isActive, isExpanded, isFocused, setFocused, userAd
61101
variant={isActive ? "primary" : "tertiary"}
62102
className="flex-shrink-0 text-sm p-1 w-28"
63103
autoFocus={isActive || isExpanded}
64-
pending={balance.status === "pending"}
104+
pending={
105+
balance.status === "pending" || allowance.status === "pending" || requestAllowance.status === "pending"
106+
}
65107
onClick={() => setFocused(true)}
66108
>
67109
Top up
@@ -70,7 +112,22 @@ export function GasBalance({ isActive, isExpanded, isFocused, setFocused, userAd
70112
<WithdrawGasBalanceButton userAddress={userAddress} />
71113
</div>
72114
</div>
73-
{isExpanded ? <p className="text-sm">Your gas balance is used to pay for onchain computation.</p> : null}
115+
{isExpanded ? (
116+
<div className="text-sm space-y-2">
117+
<p>Your gas balance is used to pay for onchain computation.</p>
118+
<p>
119+
You have{" "}
120+
<span className="font-mono">
121+
{balance.data != null ? <Balance wei={balance.data} /> : <PendingIcon className="text-sm" />}
122+
</span>{" "}
123+
in gas deposits and{" "}
124+
<span className="font-mono">
125+
{allowance.data != null ? <Balance wei={allowance.data} /> : <PendingIcon className="text-sm" />}
126+
</span>{" "}
127+
in gas grants.
128+
</p>
129+
</div>
130+
) : null}
74131
</div>
75132
);
76133
}

packages/entrykit/src/onboarding/useSetupSession.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -114,29 +114,6 @@ export function useSetupSession({ connector, userClient }: { connector: Connecto
114114
],
115115
}),
116116
);
117-
118-
// create session account instead of doing lazily
119-
await (async () => {
120-
console.log("creating session account by sending empty user op");
121-
const hash = await getAction(
122-
sessionClient,
123-
sendUserOperation,
124-
"sendUserOperation",
125-
)({
126-
calls: [{ to: zeroAddress }],
127-
});
128-
129-
const receipt = await getAction(
130-
bundlerClient,
131-
waitForUserOperationReceipt,
132-
"waitForUserOperationReceipt",
133-
)({ hash });
134-
console.log("got user op receipt", receipt);
135-
136-
if (!receipt.success) {
137-
console.error("not successful?", receipt);
138-
}
139-
})();
140117
} else if (userClient.account.type === "smart") {
141118
// Set up session for smart account wallet
142119
const calls = [];
@@ -233,6 +210,28 @@ export function useSetupSession({ connector, userClient }: { connector: Connecto
233210
}
234211
}
235212

213+
// attempt to create session smart account instead of doing lazily
214+
// so downstream can expect the session account to exist
215+
await (async () => {
216+
if (await sessionClient.account.isDeployed?.()) return;
217+
218+
console.log("creating session account by sending empty user op");
219+
const hash = await getAction(
220+
sessionClient,
221+
sendUserOperation,
222+
"sendUserOperation",
223+
)({
224+
calls: [{ to: zeroAddress }],
225+
});
226+
227+
const receipt = await getAction(
228+
sessionClient,
229+
waitForUserOperationReceipt,
230+
"waitForUserOperationReceipt",
231+
)({ hash });
232+
console.log("got user op receipt", receipt);
233+
})();
234+
236235
await Promise.all([
237236
queryClient.invalidateQueries({ queryKey: ["getSpender"] }),
238237
queryClient.invalidateQueries({ queryKey: ["getDelegation"] }),

0 commit comments

Comments
 (0)