Skip to content

Commit

Permalink
fix: paymaster (#907)
Browse files Browse the repository at this point in the history
* fix: paymaster

* fixing build

* fixing build

* fixing build

* additional testing

* fixing paymaster for deployed wallets

* fixing execute

* fixing paymaster

* fixing paymaster for argent
  • Loading branch information
Marchand-Nicolas authored Nov 12, 2024
1 parent c15caf3 commit 29f2323
Show file tree
Hide file tree
Showing 10 changed files with 3,017 additions and 2,400 deletions.
4 changes: 3 additions & 1 deletion components/UI/connectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ const ConnectButton: FunctionComponent = () => {
}, [isConnected]);

const connectWallet = async (connector: Connector) => {
await connectAsync({ connector });
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await connectAsync({ connector: connector });
localStorage.setItem("SID-connectedWallet", connector.id);
};

Expand Down
20 changes: 5 additions & 15 deletions components/UI/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import styles from "../../styles/components/navbar.module.css";
import connectStyles from "../../styles/components/walletConnect.module.css";
import Button from "./button";
import { useConnect, useAccount, useDisconnect } from "@starknet-react/core";
import { sepolia, mainnet } from "@starknet-react/chains";
import ModalMessage from "./modalMessage";
import { useDisplayName } from "../../hooks/displayName.tsx";
import { useMediaQuery } from "@mui/material";
Expand All @@ -32,16 +31,15 @@ import {
import WalletConnect from "./walletConnect";
import ArrowDownIcon from "./iconsComponents/icons/arrowDownIcon";
import errorLottie from "../../public/visuals/errorLottie.json";
import { bigintToStringHex } from "@/utils/stringService";
import { useRouter } from "next/router";
import useIsWrongNetwork from "@/hooks/isWrongNetwork";

const Navbar: FunctionComponent = () => {
const theme = useTheme();
const [nav, setNav] = useState<boolean>(false);
const [desktopNav, setDesktopNav] = useState<boolean>(false);
const { address, account } = useAccount();
const { address } = useAccount();
const [isConnected, setIsConnected] = useState<boolean>(false);
const [isWrongNetwork, setIsWrongNetwork] = useState(false);
const { connectAsync, connectors } = useConnect();
const { disconnect } = useDisconnect();
const isMobile = useMediaQuery("(max-width:425px)");
Expand All @@ -52,6 +50,7 @@ const Navbar: FunctionComponent = () => {
const [showWallet, setShowWallet] = useState<boolean>(false);
const [profile, setProfile] = useState<StarkProfile | undefined>(undefined);
const { starknetIdNavigator } = useContext(StarknetIdJsContext);
const { isWrongNetwork, setIsWrongNetwork } = useIsWrongNetwork();
const [showWalletConnectModal, setShowWalletConnectModal] =
useState<boolean>(false);
const router = useRouter();
Expand All @@ -72,6 +71,8 @@ const Navbar: FunctionComponent = () => {

const connectWallet = async (connector: Connector) => {
try {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
await connectAsync({ connector });
localStorage.setItem("SID-connectedWallet", connector.id);
localStorage.setItem("SID-lastUsedConnector", connector.id);
Expand All @@ -98,24 +99,13 @@ const Navbar: FunctionComponent = () => {
address ? setIsConnected(true) : setIsConnected(false);
}, [address]);

useEffect(() => {
if (!isConnected || !account) return;
account.getChainId().then((chainId) => {
const isWrongNetwork =
(chainId === bigintToStringHex(sepolia.id) && network === "mainnet") ||
(chainId === bigintToStringHex(mainnet.id) && network === "testnet");
setIsWrongNetwork(isWrongNetwork);
});
}, [account, network, isConnected]);

useEffect(() => {
setLastConnector(getLastConnector());
}, [isConnected]);

function disconnectByClick(): void {
disconnect();
setIsConnected(false);
setIsWrongNetwork(false);
setShowWallet(false);
localStorage.removeItem("SID-connectedWallet");
}
Expand Down
10 changes: 8 additions & 2 deletions components/discount/freeRegisterCheckout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import FreeRegisterSummary from "./freeRegisterSummary";
import { useAccount } from "@starknet-react/core";
import { Call } from "starknet";
import usePaymaster from "@/hooks/paymaster";
import useIsWrongNetwork from "@/hooks/isWrongNetwork";

type FreeRegisterCheckoutProps = {
domain: string;
Expand Down Expand Up @@ -60,6 +61,7 @@ const FreeRegisterCheckout: FunctionComponent<FreeRegisterCheckoutProps> = ({
const [signature, setSignature] = useState<string[]>(["", ""]);
const [loadingCoupon, setLoadingCoupon] = useState<boolean>(false);
const [transactionHash, setTransactionHash] = useState<string | undefined>();
const { isWrongNetwork } = useIsWrongNetwork();
const {
handleRegister,
data: registerData,
Expand Down Expand Up @@ -150,6 +152,7 @@ const FreeRegisterCheckout: FunctionComponent<FreeRegisterCheckoutProps> = ({
useEffect(() => {
if (!coupon) return setLoadingCoupon(false);
if (!address) return;
if (isWrongNetwork) return setLoadingCoupon(false);
setLoadingCallData(true);
getFreeDomain(address, `${domain}.stark`, coupon).then((res) => {
if (res.error)
Expand All @@ -163,7 +166,7 @@ const FreeRegisterCheckout: FunctionComponent<FreeRegisterCheckoutProps> = ({
}
setLoadingCoupon(false);
});
}, [coupon, domain, address]);
}, [coupon, domain, address, isWrongNetwork]);

return (
<div className={styles.container}>
Expand Down Expand Up @@ -205,6 +208,7 @@ const FreeRegisterCheckout: FunctionComponent<FreeRegisterCheckoutProps> = ({
<Button
onClick={handleRegister}
disabled={
isWrongNetwork ||
(domainsMinting.get(encodedDomain) as boolean) ||
!account ||
!coupon ||
Expand All @@ -218,7 +222,9 @@ const FreeRegisterCheckout: FunctionComponent<FreeRegisterCheckoutProps> = ({
loadingTypedData
}
>
{!termsBox
{isWrongNetwork
? "Wrong Network"
: !termsBox
? "Please accept terms & policies"
: couponError || !coupon
? "Enter a valid Coupon"
Expand Down
25 changes: 25 additions & 0 deletions hooks/isWrongNetwork.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { mainnet } from "@starknet-react/chains";
import { bigintToStringHex } from "@/utils/stringService";
import { sepolia } from "@starknet-react/chains";
import { useNetwork } from "@starknet-react/core";
import { useEffect, useState } from "react";

const useIsWrongNetwork = () => {
const { chain } = useNetwork();
const [isWrongNetwork, setIsWrongNetwork] = useState<boolean>(false);

useEffect(() => {
setIsWrongNetwork(
process.env.NEXT_PUBLIC_IS_TESTNET === "true"
? bigintToStringHex(chain.id) === bigintToStringHex(mainnet.id)
: bigintToStringHex(chain.id) === bigintToStringHex(sepolia.id)
);
}, [chain]);

return {
isWrongNetwork,
setIsWrongNetwork,
};
};

export default useIsWrongNetwork;
124 changes: 57 additions & 67 deletions hooks/paymaster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import {
getGasFeesInGasToken,
GasTokenPrice,
fetchGasTokenPrices,
executeCalls,
} from "@avnu/gasless-sdk";
import {
useProvider,
useAccount,
useConnect,
useSendTransaction,
useSignTypedData,
} from "@starknet-react/core";
import {
AccountInterface,
Expand Down Expand Up @@ -54,15 +54,18 @@ const usePaymaster = (
});
const { connector } = useConnect();
const { isDeployed, deploymentData } = isStarknetDeployed(account?.address);
const [deploymentTypedData, setDeploymentTypedData] = useState<TypedData>();
const [typedData, setTypedData] = useState<TypedData>();
const [invalidTx, setInvalidTx] = useState<boolean>(false);
const [txError, setTxError] = useState<ErrorMessage>();
const { signTypedDataAsync } = useSignTypedData({});

const argentWallet = useMemo(
() => connector?.id === "argentX" /*|| connector?.id === "argentMobile"*/,
[connector]
);

const paymasterEnabled = !argentWallet;

useEffect(() => {
if (!gasTokenPrice) setGasTokenPrice(gasTokenPrices[0]);
}, [gasTokenPrice, gasTokenPrices]);
Expand Down Expand Up @@ -130,8 +133,14 @@ const usePaymaster = (
}, []);

useEffect(() => {
if (!account || !gasTokenPrice || !gaslessCompatibility || loadingCallData)
return;
if (
!account ||
!gasTokenPrice ||
!gaslessCompatibility ||
loadingCallData ||
!paymasterEnabled
)
return setLoadingGas(false);
setLoadingGas(true);
setInvalidTx(false);
estimateCalls(account, callData).then((fees) => {
Expand All @@ -155,35 +164,36 @@ const usePaymaster = (
gaslessCompatibility,
estimateCalls,
loadingCallData,
paymasterEnabled,
]);

const loadingDeploymentData =
connector?.id === "argentX" && !isDeployed && !deploymentData;

useEffect(() => {
if (!account) return;
if (
!account ||
isDeployed ||
!deploymentData ||
!argentWallet ||
loadingDeploymentData
!isDeployed &&
(!deploymentData || !argentWallet || loadingDeploymentData)
)
return;
const body: { [id: string]: object | string } = {
userAddress: account.address,
calls: callData,
};
if (!isDeployed && deploymentData)
body.accountClassHash = deploymentData.class_hash;
fetch(`${gaslessOptions.baseUrl}/gasless/v1/build-typed-data`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
userAddress: account.address,
calls: callData,
accountClassHash: deploymentData.class_hash,
}),
body: JSON.stringify(body),
})
.then((res) => res.json())
.then((data) => {
if (data.messages || data.error) return;
setDeploymentTypedData(data);
setTypedData(data);
})
.catch((error) => {
console.error("Error when fetching deployment typed data:", error);
Expand All @@ -198,62 +208,42 @@ const usePaymaster = (
loadingDeploymentData,
]);

const handleRegister = () => {
const handleRegister = useCallback(() => {
if (!account) return;
if (argentWallet && (connector?.id !== "argentMobile" || isDeployed)) {
if (deploymentData && deploymentTypedData) {
account
.signMessage(
deploymentTypedData,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
{ skipDeploy: true }
)
.then((signature: Signature) => {
fetch(`${gaslessOptions.baseUrl}/gasless/v1/execute`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
userAddress: account.address,
typedData: JSON.stringify(deploymentTypedData),
signature: (signature as string[]).map(decimalToHex),
deploymentData,
}),
})
.then((res) => res.json())
.then((data) => {
return then(data.transactionHash);
})
.catch((error) => {
console.error(
"Error when executing (including deployment) with Paymaster:",
error
);
});
});
} else
executeCalls(
account,
callData,
paymasterRewards.length === 0
? {
gasTokenAddress: gasTokenPrice?.tokenAddress,
maxGasTokenAmount,
}
: {},
gaslessOptions
)
.then((res) => then(res.transactionHash))
if (typedData && !argentWallet) {
signTypedDataAsync(typedData).then((signature: Signature) => {
const body: { [id: string]: object | string } = {
userAddress: account.address,
typedData: JSON.stringify(typedData),
signature: (signature as string[]).map(decimalToHex),
};
if (!isDeployed && deploymentData) body.deploymentData = deploymentData;
fetch(`${gaslessOptions.baseUrl}/gasless/v1/execute`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
})
.then((res) => res.json())
.then((data) => {
return then(data.transactionHash);
})
.catch((error) => {
console.error("Error when executing with Paymaster:", error);
});
});
} else execute().then((res) => then(res.transaction_hash));
};

const loadingTypedData =
connector?.id !== "argentMobile" && deploymentData && !deploymentTypedData;
}, [
account,
deploymentData,
then,
signTypedDataAsync,
typedData,
execute,
isDeployed,
argentWallet,
]);

return {
handleRegister,
Expand All @@ -268,7 +258,7 @@ const usePaymaster = (
loadingDeploymentData,
refreshRewards,
invalidTx,
loadingTypedData,
loadingTypedData: !typedData && isDeployed && paymasterEnabled,
txError,
};
};
Expand Down
Loading

0 comments on commit 29f2323

Please sign in to comment.