diff --git a/components/UI/connectButton.tsx b/components/UI/connectButton.tsx
index a9c0ff63..ed7ef2fb 100644
--- a/components/UI/connectButton.tsx
+++ b/components/UI/connectButton.tsx
@@ -40,7 +40,7 @@ const ConnectButton: FunctionComponent = () => {
className={styles.btnIcon}
/>
) : null}
-
Connect wallet
+ Connect wallet
{lastConnector ? (
{
const theme = useTheme();
@@ -53,6 +54,13 @@ const Navbar: FunctionComponent = () => {
const { starknetIdNavigator } = useContext(StarknetIdJsContext);
const [showWalletConnectModal, setShowWalletConnectModal] =
useState(false);
+ const router = useRouter();
+
+ useEffect(() => {
+ const pageName = router.pathname.split("/")[1];
+ if (pageName !== "gift" && pageName !== "register") return;
+ if (isMobile) setShowWalletConnectModal(true);
+ }, [isMobile, router.pathname]);
const [lastConnector, setLastConnector] = useState(null);
// could be replaced by a useProfileData from starknet-react when updated
diff --git a/components/discount/freeRegisterCheckout.tsx b/components/discount/freeRegisterCheckout.tsx
index 6b89dfd4..353dc34e 100644
--- a/components/discount/freeRegisterCheckout.tsx
+++ b/components/discount/freeRegisterCheckout.tsx
@@ -63,23 +63,21 @@ const FreeRegisterCheckout: FunctionComponent = ({
handleRegister,
data: registerData,
paymasterRewards,
- gasTokenPrices,
- gasTokenPrice,
loadingGas,
- gasMethod,
- setGasMethod,
- gaslessCompatibility,
- setGasTokenPrice,
- sponsoredDeploymentAvailable,
- maxGasTokenAmount,
loadingDeploymentData,
- } = usePaymaster(callData, async (transactionHash) => {
- setDomainsMinting((prev) =>
- new Map(prev).set(encodedDomain.toString(), true)
- );
- console.log(transactionHash);
- if (transactionHash) setTransactionHash(transactionHash);
- });
+ refreshRewards,
+ invalidTx,
+ loadingTypedData,
+ } = usePaymaster(
+ callData,
+ async (transactionHash) => {
+ setDomainsMinting((prev) =>
+ new Map(prev).set(encodedDomain.toString(), true)
+ );
+ if (transactionHash) setTransactionHash(transactionHash);
+ },
+ !coupon
+ );
useEffect(() => {
if (!registerData?.transaction_hash) return;
@@ -95,6 +93,11 @@ const FreeRegisterCheckout: FunctionComponent = ({
if (address) setTargetAddress(address);
}, [address]);
+ useEffect(() => {
+ if (loadingCoupon || !coupon) return;
+ refreshRewards();
+ }, [loadingCoupon, coupon, refreshRewards, address]);
+
useEffect(() => {
// salt must not be empty to preserve privacy
if (!salt) return;
@@ -104,11 +107,11 @@ const FreeRegisterCheckout: FunctionComponent = ({
}, [salt]);
useEffect(() => {
+ if (signature[0] === null) return;
// Variables
const newTokenId: number = Math.floor(Math.random() * 1000000000000);
setTokenId(newTokenId);
const txMetadataHash = `0x${metadataHash}` as HexString;
-
const freeRegisterCalls = registrationCalls.getFreeRegistrationCalls(
newTokenId,
encodedDomain,
@@ -142,11 +145,7 @@ const FreeRegisterCheckout: FunctionComponent = ({
}, [transactionHash, tokenId]);
useEffect(() => {
- if (!coupon) {
- setCouponError("Please enter a coupon code");
- setLoadingCoupon(false);
- return;
- }
+ if (!coupon) return setLoadingCoupon(false);
const lastSuccessCoupon = localStorage.getItem("lastSuccessCoupon");
if (coupon === lastSuccessCoupon) {
setCouponError("");
@@ -199,21 +198,7 @@ const FreeRegisterCheckout: FunctionComponent = ({
-
0}
- gasTokenPrices={gasTokenPrices}
- gasTokenPrice={gasTokenPrice}
- setGasTokenPrice={setGasTokenPrice}
- gasMethod={gasMethod}
- setGasMethod={setGasMethod}
- paymasterAvailable={
- gaslessCompatibility?.isCompatible || sponsoredDeploymentAvailable
- }
- maxGasTokenAmount={maxGasTokenAmount}
- deployed={gaslessCompatibility?.isCompatible}
- />
+
= ({
disabled={
(domainsMinting.get(encodedDomain) as boolean) ||
!account ||
+ !coupon ||
!duration ||
!targetAddress ||
!termsBox ||
Boolean(couponError) ||
loadingCoupon ||
loadingGas ||
- loadingDeploymentData
+ loadingDeploymentData ||
+ loadingTypedData
}
>
{!termsBox
? "Please accept terms & policies"
- : couponError
+ : couponError || !coupon
? "Enter a valid Coupon"
: loadingGas
- ? "Loading gas"
+ ? invalidTx
+ ? "Invalid signature"
+ : "Loading gas"
+ : loadingTypedData
+ ? "Building typed data"
: loadingDeploymentData
? paymasterRewards.length > 0
? "Loading deployment data"
diff --git a/components/discount/freeRegisterSummary.tsx b/components/discount/freeRegisterSummary.tsx
index cf9bbe8e..0bfb3da3 100644
--- a/components/discount/freeRegisterSummary.tsx
+++ b/components/discount/freeRegisterSummary.tsx
@@ -2,48 +2,23 @@ import React, { FunctionComponent } from "react";
import styles from "../../styles/components/registerV3.module.css";
import { getYearlyPrice } from "@/utils/priceService";
import DoneIcon from "../UI/iconsComponents/icons/doneIcon";
-import { GasTokenPrice } from "@avnu/gasless-sdk";
-import { tokenNames } from "@/utils/altcoinService";
-import { shortenDomain } from "@/utils/stringService";
-import StyledToolTip from "../UI/styledTooltip";
-import { GasMethod } from "@/hooks/paymaster";
-import { Alert } from "@mui/material";
+import { useAccount } from "@starknet-react/core";
type FreeRegisterSummaryProps = {
duration: number;
domain: string;
- hasPaymasterRewards?: boolean;
- gasTokenPrices?: GasTokenPrice[];
- gasTokenPrice?: GasTokenPrice;
- setGasTokenPrice: (price: GasTokenPrice) => void;
- gasMethod: GasMethod;
- setGasMethod: (method: GasMethod) => void;
- paymasterAvailable: boolean;
- maxGasTokenAmount?: bigint;
- deployed?: boolean;
};
const FreeRegisterSummary: FunctionComponent = ({
domain,
duration,
- hasPaymasterRewards,
- gasTokenPrices,
- gasTokenPrice,
- setGasTokenPrice,
- gasMethod,
- setGasMethod,
- paymasterAvailable,
- maxGasTokenAmount,
- deployed,
}) => {
+ const { address } = useAccount();
+
function getMessage() {
return `${Math.floor(duration / 30)} months of domain registration`;
}
- const getTokenName = (price: GasTokenPrice) =>
- tokenNames[price.tokenAddress as keyof typeof tokenNames] ||
- shortenDomain(price.tokenAddress);
-
return (
@@ -56,112 +31,22 @@ const FreeRegisterSummary: FunctionComponent = ({
Free
-
- setGasMethod("traditional")}
- className={
- gasMethod === "traditional"
- ? styles.gasMethodSelected
- : styles.gasMethod
- }
- type="button"
- >
- Traditional Transaction
-
-
- setGasMethod("paymaster")}
- className={
- gasMethod === "paymaster"
- ? styles.gasMethodSelected
- : styles.gasMethod
- }
- type="button"
- disabled={!paymasterAvailable}
- >
- Gasless Transaction
-
-
-
- {gasMethod === "paymaster" ? (
- hasPaymasterRewards ? (
-
-
-
- No gas fees to pay. You have a{" "}
-
- Paymaster
- {" "}
- reward.
-
-
- ) : (
-
-
- No{" "}
-
- Paymaster
- {" "}
- reward. {deployed ? "Please select a gas token." : ""}
-
- {deployed ? (
- <>
-
- {gasTokenPrices?.map((price) => (
- setGasTokenPrice(price)}
- key={price.tokenAddress}
- className={
- price.tokenAddress === gasTokenPrice?.tokenAddress
- ? styles.gasMethodSelected
- : styles.gasMethod
- }
- type="button"
- >
- {getTokenName(price)}{" "}
-
- ))}
-
- {gasTokenPrice ? (
-
- {maxGasTokenAmount
- ? `Please make sure to have at least ${maxGasTokenAmount.toString()} ${getTokenName(
- gasTokenPrice
- )} to prevent transaction failure.`
- : `Please make sure to have enough ${getTokenName(
- gasTokenPrice
- )} to prevent transaction failure.`}
-
- ) : null}
- >
- ) : (
-
- Your wallet is not deployed. To sponsor its deployment, please
- gather rewards.
-
- )}
-
- )
+ {address ? (
+
+
+
+ No gas fees to pay. You have a{" "}
+
+ Paymaster
+ {" "}
+ reward.
+
+
) : null}
diff --git a/hooks/isDeployed.tsx b/hooks/isDeployed.tsx
index 037e90a0..25c57a5d 100644
--- a/hooks/isDeployed.tsx
+++ b/hooks/isDeployed.tsx
@@ -10,9 +10,26 @@ export default function isStarknetDeployed(address?: string) {
const [isDeployed, setIsDeployed] = useState(false);
const [deploymentData, setDeploymentData] =
useState();
+ const [nonDeployedAddress, setNonDeployedAddress] = useState();
+ const [reload, setReload] = useState(false);
useEffect(() => {
- if (!address || !provider || !connector?.id) return;
+ if (isDeployed || deploymentData) return;
+ const interval = setInterval(() => {
+ setReload(true);
+ }, 3000);
+ return () => clearInterval(interval);
+ }, [isDeployed, deploymentData]);
+
+ useEffect(() => {
+ if (reload) return setReload(false);
+ if (
+ !address ||
+ !provider ||
+ !connector?.id ||
+ address === nonDeployedAddress
+ )
+ return;
const checkIsDeployed = async () => {
try {
provider
@@ -33,7 +50,6 @@ export default function isStarknetDeployed(address?: string) {
setDeploymentData(undefined);
return;
}
-
availableWallets.forEach(async (connectedWallet) => {
if (
connectedWallet.id === connector?.id &&
@@ -47,6 +63,7 @@ export default function isStarknetDeployed(address?: string) {
);
if (isGetDeploymentDataResult(data)) {
setDeploymentData(data);
+ setNonDeployedAddress(address);
} else {
console.error(
"Received data is not in the expected format:",
@@ -63,7 +80,7 @@ export default function isStarknetDeployed(address?: string) {
};
checkIsDeployed();
- }, [address, provider, connector?.id]);
+ }, [address, provider, connector?.id, nonDeployedAddress, reload]);
return { isDeployed, deploymentData };
}
diff --git a/hooks/paymaster.tsx b/hooks/paymaster.tsx
index 8204a829..be15b6f7 100644
--- a/hooks/paymaster.tsx
+++ b/hooks/paymaster.tsx
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useState } from "react";
+import { useCallback, useEffect, useMemo, useState } from "react";
import {
fetchAccountCompatibility,
fetchAccountsRewards,
@@ -7,14 +7,13 @@ import {
getGasFeesInGasToken,
GasTokenPrice,
fetchGasTokenPrices,
- fetchGaslessStatus,
executeCalls,
} from "@avnu/gasless-sdk";
import {
- useContractWrite,
useProvider,
useAccount,
useConnect,
+ useContractWrite,
} from "@starknet-react/core";
import {
AccountInterface,
@@ -29,83 +28,63 @@ import isStarknetDeployed from "./isDeployed";
import { gaslessOptions } from "@/utils/constants";
import { decimalToHex } from "@/utils/feltService";
-export type GasMethod = "traditional" | "paymaster";
-
const usePaymaster = (
callData: Call[],
- then: (transactionHash: string) => void
+ then: (transactionHash: string) => void,
+ loadingCallData: boolean
) => {
const { account } = useAccount();
- const [gaslessAPIAvailable, setGaslessAPIAvailable] = useState(true);
const [gaslessCompatibility, setGaslessCompatibility] =
useState();
const [gasTokenPrices, setGasTokenPrices] = useState([]);
const [maxGasTokenAmount, setMaxGasTokenAmount] = useState();
- const [gasMethod, setGasMethod] = useState("traditional");
const { provider } = useProvider();
const [paymasterRewards, setPaymasterRewards] = useState(
[]
);
const [gasTokenPrice, setGasTokenPrice] = useState();
const [loadingGas, setLoadingGas] = useState(false);
- const [sponsoredDeploymentAvailable, setSponsoredDeploymentAvailable] =
- useState(false);
const { writeAsync: execute, data } = useContractWrite({
calls: callData,
});
const { connector } = useConnect();
const { isDeployed, deploymentData } = isStarknetDeployed(account?.address);
const [deploymentTypedData, setDeploymentTypedData] = useState();
+ const [invalidTx, setInvalidTx] = useState(false);
- useEffect(() => {
- if (!account || !connector) return;
- setSponsoredDeploymentAvailable(
- connector.id === "argentX" || connector.id === "argentMobile"
- );
- }, [account, connector]);
+ const argentWallet = useMemo(
+ () => connector?.id === "argentX" /*|| connector?.id === "argentMobile"*/,
+ [connector]
+ );
useEffect(() => {
if (!gasTokenPrice) setGasTokenPrice(gasTokenPrices[0]);
}, [gasTokenPrice, gasTokenPrices]);
- useEffect(() => {
- if (gaslessCompatibility?.isCompatible && paymasterRewards.length > 0)
- setGasMethod("paymaster");
- }, [gaslessCompatibility, paymasterRewards]);
-
- useEffect(() => {
- if (!gaslessCompatibility?.isCompatible) setGasMethod("traditional");
- }, [gaslessCompatibility]);
-
- useEffect(() => {
- fetchGaslessStatus(gaslessOptions).then((res) => {
- setGaslessAPIAvailable(res.status);
- });
- }, []);
-
- useEffect(() => {
- if (gasMethod === "traditional" && loadingGas) setLoadingGas(false);
- }, [gasMethod, loadingGas]);
+ const refreshRewards = useCallback(() => {
+ if (!account) return;
+ fetchAccountsRewards(account.address, {
+ ...gaslessOptions,
+ protocol: "STARKNETID",
+ }).then(setPaymasterRewards);
+ }, [account]);
useEffect(() => {
- if (!account || !gaslessAPIAvailable) return;
+ if (!account) return;
fetchAccountCompatibility(account.address, gaslessOptions)
.then(setGaslessCompatibility)
.catch((e) => {
setGaslessCompatibility(undefined);
console.error(e);
});
- fetchAccountsRewards(account.address, {
- ...gaslessOptions,
- protocol: "STARKNETID",
- }).then(setPaymasterRewards);
- }, [account, gaslessAPIAvailable]);
+ refreshRewards();
+ }, [account, refreshRewards]);
const estimateCalls = useCallback(
async (
account: AccountInterface,
calls: Call[]
- ): Promise => {
+ ): Promise => {
const contractVersion = await provider.getContractVersion(
account.address
);
@@ -117,12 +96,17 @@ const usePaymaster = (
calldata: transaction.getExecuteCalldata(calls, contractVersion.cairo),
signature: [],
};
- return provider.getInvokeEstimateFee(
- { ...invocation },
- { ...details, nonce },
- "pending",
- true
- );
+ return provider
+ .getInvokeEstimateFee(
+ { ...invocation },
+ { ...details, nonce },
+ "pending",
+ true
+ )
+ .catch((e) => {
+ console.error(e);
+ setInvalidTx(true);
+ });
},
[provider]
);
@@ -136,16 +120,12 @@ const usePaymaster = (
}, []);
useEffect(() => {
- if (
- !account ||
- !gasTokenPrice ||
- !gaslessCompatibility ||
- !gaslessAPIAvailable ||
- gasMethod === "traditional"
- )
+ if (!account || !gasTokenPrice || !gaslessCompatibility || loadingCallData)
return;
setLoadingGas(true);
estimateCalls(account, callData).then((fees) => {
+ if (!fees) return;
+ setInvalidTx(false);
const estimatedGasFeesInGasToken = getGasFeesInGasToken(
BigInt(fees.overall_fee),
gasTokenPrice,
@@ -158,21 +138,24 @@ const usePaymaster = (
setLoadingGas(false);
});
}, [
- gasMethod,
callData,
account,
gasTokenPrice,
gaslessCompatibility,
estimateCalls,
- gaslessAPIAvailable,
+ loadingCallData,
]);
+ const loadingDeploymentData =
+ connector?.id !== "argentMobile" && !isDeployed && !deploymentData;
+
useEffect(() => {
if (
!account ||
isDeployed ||
!deploymentData ||
- !sponsoredDeploymentAvailable
+ !argentWallet ||
+ loadingDeploymentData
)
return;
fetch(`${gaslessOptions.baseUrl}/gasless/v1/build-typed-data`, {
@@ -188,7 +171,7 @@ const usePaymaster = (
})
.then((res) => res.json())
.then((data) => {
- if (data.messages) return;
+ if (data.messages || data.error) return;
setDeploymentTypedData(data);
})
.catch((error) => {
@@ -198,14 +181,15 @@ const usePaymaster = (
account,
isDeployed,
deploymentData,
- sponsoredDeploymentAvailable,
+ argentWallet,
callData,
maxGasTokenAmount,
+ loadingDeploymentData,
]);
const handleRegister = () => {
if (!account) return;
- if (gasMethod === "paymaster") {
+ if (argentWallet && (connector?.id !== "argentMobile" || isDeployed)) {
if (deploymentData && deploymentTypedData) {
account
.signMessage(
@@ -232,7 +216,10 @@ const usePaymaster = (
return then(data.transactionHash);
})
.catch((error) => {
- console.error("Error when executing with Paymaster:", error);
+ console.error(
+ "Error when executing (including deployment) with Paymaster:",
+ error
+ );
});
});
} else
@@ -254,8 +241,8 @@ const usePaymaster = (
} else execute().then((res) => then(res.transaction_hash));
};
- const loadingDeploymentData =
- !isDeployed && !deploymentTypedData && gasMethod === "paymaster";
+ const loadingTypedData =
+ connector?.id !== "argentMobile" && deploymentData && !deploymentTypedData;
return {
handleRegister,
@@ -265,12 +252,12 @@ const usePaymaster = (
gasTokenPrice,
loadingGas,
setGasTokenPrice,
- gasMethod,
- setGasMethod,
gaslessCompatibility,
- sponsoredDeploymentAvailable,
maxGasTokenAmount,
loadingDeploymentData,
+ refreshRewards,
+ invalidTx,
+ loadingTypedData,
};
};