}
+ productName={"simulation"}
registerStream={addStreams}
renderReasonCode={renderReasonCode}
handleTransactionStatus={handleTransactionStatus}
- tokenList={tokenList}
- cart={
diff --git a/ui/app/src/StreamPage.tsx b/ui/app/src/StreamPage.tsx
index da911ab..6271061 100644
--- a/ui/app/src/StreamPage.tsx
+++ b/ui/app/src/StreamPage.tsx
@@ -6,9 +6,9 @@ import { ConnectButton } from "@rainbow-me/rainbowkit";
import "./styles.css";
import StreamManager, { Stream } from "@apeworx/apepay";
import {
- CancelStream,
UpdateStream,
StreamStatus,
+ CancelStream,
} from "@apeworx/apepay-react";
import {
usePublicClient,
@@ -80,13 +80,13 @@ const StreamPage = () => {
}, [SM, address, walletClient]);
const [streamInfo, setStreamInfo] = useState({
+ token: null as string | null,
amountPerSecond: null as bigint | null,
+ maxStreamLife: null as bigint | null,
fundedAmount: null as bigint | null,
+ startTime: null as bigint | null,
lastPull: null as bigint | null,
- maxStreamLife: null as bigint | null,
reason: null as Uint8Array | null,
- startTime: null as bigint | null,
- token: null as string | null,
});
// Get info about your stream
@@ -96,13 +96,13 @@ const StreamPage = () => {
.streamInfo()
.then((info) => {
setStreamInfo({
+ token: info.token,
amountPerSecond: info.amount_per_second,
+ maxStreamLife: info.max_stream_life,
fundedAmount: info.funded_amount,
+ startTime: info.start_time,
lastPull: info.last_pull,
- maxStreamLife: info.max_stream_life,
reason: info.reason,
- startTime: info.start_time,
- token: info.token,
});
})
.catch((error) => {
diff --git a/ui/app/src/config.ts b/ui/app/src/config.ts
index 513cf34..9dcd4a5 100644
--- a/ui/app/src/config.ts
+++ b/ui/app/src/config.ts
@@ -1,7 +1,7 @@
// Override this config in your downstream implementations as needed
const config = {
- fromBlock: 4615000,
+ fromBlock: 4900000,
streamManagerAddress: "0x3543Faeeddb7bAbCbBB216B3627f9c5E0C39CE41",
tokens: [
{
diff --git a/ui/lib/CreateStream.tsx b/ui/lib/CreateStream.tsx
index 87ca2c0..80e970a 100644
--- a/ui/lib/CreateStream.tsx
+++ b/ui/lib/CreateStream.tsx
@@ -10,6 +10,7 @@ import {
useContractWrite,
useWaitForTransaction,
useNetwork,
+ useContractRead,
} from "wagmi";
import { fetchBalance } from "@wagmi/core";
import StreamManager, { Stream } from "@apeworx/apepay";
@@ -23,6 +24,7 @@ export interface CreateStreamProps {
tokenList: TokenInfo[];
amountPerSecond: bigint;
cart?: ReactNode;
+ productName?: string;
registerStream: (stream: Stream) => void;
renderReasonCode: () => Promise
;
handleTransactionStatus: (
@@ -246,12 +248,60 @@ const CreateStream = (props: CreateStreamProps) => {
}
}, [props.tokenList, targetChainId]);
+ const [isAllowanceSufficient, setIsAllowanceSufficient] =
+ useState(false);
+
+ // ABI used to fetch the current user allowance
+ const erc20ABI = [
+ {
+ constant: true,
+ inputs: [
+ { name: "_owner", type: "address" },
+ { name: "_spender", type: "address" },
+ ],
+ name: "allowance",
+ outputs: [{ name: "", type: "uint256" }],
+ type: "function",
+ },
+ ];
+
+ // Fetch current user allowance
+ const { data: allowanceData } = useContractRead({
+ address: selectedToken?.address as Address,
+ functionName: "allowance",
+ abi: erc20ABI,
+ args: [address, props.streamManagerAddress],
+ watch: true,
+ onError(error) {
+ console.log("Error fetching allowance", error);
+ },
+ onSettled(data, error) {
+ console.log("Allowance settled", { data, error });
+ },
+ });
+
+ useEffect(() => {
+ // Check if allowance data is available and update allowance state
+ if (allowanceData !== null && allowanceData !== undefined) {
+ const fetchedAllowance = Number(allowanceData.toString());
+
+ // Check if the fetched allowance is sufficient for the transaction cost
+ if (txCost !== undefined) {
+ setIsAllowanceSufficient(fetchedAllowance >= txCost);
+ }
+ }
+ }, [allowanceData, txCost]);
+
// Select the payment token among tokens with the same chainID
const Step1 = () => {
return (
{props.cart && props.cart}
+
+ {" "}
+ Select a token to pay for your {props.productName || "Stream"}{" "}
+
{
{props.cart && props.cart}
- Fetching stream manager address...
+ Fetching contract address...
@@ -391,6 +441,10 @@ const CreateStream = (props: CreateStreamProps) => {
{props.cart && props.cart}
+
+ Select the number of days you want to run your{" "}
+ {props.productName || "Stream"}
+
{
}
disabled={isSuccess}
/>
-
- {`Approve ${Math.floor(transactionAmount + 1)}`}
- {`${selectedToken?.symbol}`}
-
+ {isAllowanceSufficient ? (
+
+ {`Run ${props.productName || "Stream"} for ${
+ selectedTime / SECS_PER_DAY
+ } day${selectedTime !== SECS_PER_DAY ? "s" : ""}`}
+
+ ) : (
+
+ {`Approve ${Math.floor(transactionAmount + 1)}`}{" "}
+ {`${selectedToken?.symbol}`}
+
+ )}
{isLoading && (
Waiting for your confirmation.
@@ -425,8 +491,8 @@ const CreateStream = (props: CreateStreamProps) => {
)}
{txLoading && (
- Transaction approved: you will be redirected once it has been
- processed...
+ Transaction approved: you will move to the next step once it has
+ been processed...
)}
{txError && (
@@ -454,9 +520,9 @@ const CreateStream = (props: CreateStreamProps) => {
onClick={createStream}
disabled={buttonCreateClicked}
>
- {`Open Stream for ${selectedTime / SECS_PER_DAY} day${
- selectedTime !== SECS_PER_DAY ? "s" : ""
- }`}
+ {`Run ${props.productName || "Stream"} for ${
+ selectedTime / SECS_PER_DAY
+ } day${selectedTime !== SECS_PER_DAY ? "s" : ""}`}
diff --git a/ui/lib/UpdateStream.tsx b/ui/lib/UpdateStream.tsx
index 9ce7254..5306c9a 100644
--- a/ui/lib/UpdateStream.tsx
+++ b/ui/lib/UpdateStream.tsx
@@ -3,6 +3,7 @@ import { Stream } from "@apeworx/apepay";
import {
usePrepareContractWrite,
useContractWrite,
+ useContractRead,
useAccount,
useBalance,
} from "wagmi";
@@ -83,6 +84,50 @@ const UpdateStream: React.FC
= (props) => {
}
}, [isSuccess]);
+ const [isAllowanceSufficient, setIsAllowanceSufficient] =
+ useState(false);
+
+ // ABI used to fetch the current user allowance
+ const erc20ABI = [
+ {
+ constant: true,
+ inputs: [
+ { name: "_owner", type: "address" },
+ { name: "_spender", type: "address" },
+ ],
+ name: "allowance",
+ outputs: [{ name: "", type: "uint256" }],
+ type: "function",
+ },
+ ];
+
+ // Fetch current user allowance
+ const { data: allowanceData } = useContractRead({
+ address: props.stream.token,
+ functionName: "allowance",
+ abi: erc20ABI,
+ args: [address, props.stream.streamManager.address],
+ watch: true,
+ onError(error) {
+ console.log("Error fetching allowance", error);
+ },
+ onSettled(data, error) {
+ console.log("Allowance settled", { data, error });
+ },
+ });
+
+ useEffect(() => {
+ // Check if allowance data is available and update allowance state
+ if (allowanceData !== null && allowanceData !== undefined) {
+ const fetchedAllowance = Number(allowanceData.toString());
+
+ // Check if the fetched allowance is sufficient for the transaction cost
+ if (contractAmount !== undefined) {
+ setIsAllowanceSufficient(fetchedAllowance >= contractAmount);
+ }
+ }
+ }, [allowanceData, contractAmount]);
+
// Step 1: set number of tokens you want to add
const Step1 = () => {
return (
@@ -102,11 +147,26 @@ const UpdateStream: React.FC = (props) => {
typeof value === "number" && setSelectedTime(value)
}
/>
-
- {`Validate adding funds for ${selectedTime} additional day${
- selectedTime !== 1 ? "s" : ""
- }`}
-
+ {isAllowanceSufficient ? (
+
+ {`Add funds for ${selectedTime} additional day${
+ selectedTime !== 1 ? "s" : ""
+ }`}
+
+ ) : (
+
+ {`Validate adding funds for ${selectedTime} additional day${
+ selectedTime !== 1 ? "s" : ""
+ }`}
+
+ )}
>
) : (
<>