I have to pass token amount as argument on a function call. The amount is dynamic and coming from a text box when a user click button (for partial amount submission). There is another button that allow to submit all available token amount.
So if total token amount is 5000. A user can input any amount in between 1 to 5000 in text box and click the button which invoke write
function from useContractWrite
hook. And then there is another button that when clicked by the user should pass 5000 as argument and invoke write
function.
Below are the 2 approaches I tired, but both is not working. I have commented the respective part of my code to make my point more clear.
1st approach (Using state hook)
import { BigNumber, utils } from "ethers";
import React, { useEffect, useState } from "react";
import {
usePrepareContractWrite,
useContractWrite,
useWaitForTransaction,
} from "wagmi";
import { useDebounce } from "@/hooks/usehooks";
import {
tokenAddress,
tokenAbi,
} from "../../constants/Token";
const submitToken: React.FC = ({tokenAmount}) => {
const [partialAmount, setPartialAmount] = useState<string>("0");
const [totalTokenAmount, setTotalTokenAmount] = useState<number>(tokenAmount);
const [amountToPut, setAmountToPut] = useState<BigNumber>(
BigNumber.from("0")
); // this state is argument
const debountAmount = useDebounce(partialAmount, 500); //rate limiting
const {
config,
error: prepareError,
isError: isPrepareError,
} = usePrepareContractWrite({
address: tokenAddress,
abi: tokenAbi,
functionName: "myWritableFun",
args: [amountToPut], // This doesn't update when we change the `partialAmount` in function below
});
const {
data,
error: contractError,
isError: isContractError,
write,
} = useContractWrite(config);
const { isLoading, isSuccess } = useWaitForTransaction({
hash: data?.hash,
});
const putPartialToken = () => {
if (isNaN(Number(debountAmount))) {
alert("Not a valid amount");
return;
}
// we are checking this in contract too
if (Number(debountAmount) > totalTokenAmount) {
alert("Amount overflow!");
return;
}
//the below doesn't work on first click So,basically this is where I am not sure how to set `amountToPut`
setAmountToPut(utils.parseEther(debountAmount));
write?.();
};
const putAllToken = async () => {
setAmountToPut(utils.parseEther(totalTokenAmount.toString()));
write?.();
};
return (
<div>
<p>
Submit All token{" "}
{/* Submit all amount, first event */}
<button onClick={putAllToken} disabled={!write || isLoading}>
Submit All Amount
</button>
</p>
<p>
Sumbit partial amount
<input
type="text"
id="partialSubmit"
onChange={(e) => setPartialAmount(e.target.value)}
/>
{/* Submit partial amount, second event */}
<button onClick={putPartialToken} disabled={!write || isLoading}>
Submit Partial Amount
</button>
</p>
</div>
);
};
export default submitToken;
The 2nd approach (using a variable)
import { BigNumber, utils } from "ethers";
import React, { useEffect, useState } from "react";
import {
usePrepareContractWrite,
useContractWrite,
useWaitForTransaction,
} from "wagmi";
import { useDebounce } from "@/hooks/usehooks";
import {
tokenAddress,
tokenAbi,
} from "../../constants/Token";
const submitToken: React.FC = ({tokenAmount}) => {
const [partialAmount, setPartialAmount] = useState<string>("0");
const [totalTokenAmount, setTotalTokenAmount] = useState<number>(tokenAmount);
const debountAmount = useDebounce(partialAmount, 500); //rate limiting
// I am using variable instead of state
let amountToPut = utils.parseEther("0");
const {
config,
error: prepareError,
isError: isPrepareError,
} = usePrepareContractWrite({
address: tokenAddress,
abi: tokenAbi,
functionName: "myWritableFun",
args: [amountToPut], // This doesn't update when we change the `partialAmount` in function below
});
const {
data,
error: contractError,
isError: isContractError,
write,
} = useContractWrite(config);
const { isLoading, isSuccess } = useWaitForTransaction({
hash: data?.hash,
});
const putPartialToken = () => {
if (isNaN(Number(debountAmount))) {
alert("Not a valid amount");
return;
}
// we are checking this in contract too
if (Number(debountAmount) > totalTokenAmount) {
alert("Amount overflow!");
return;
}
//This does change the value of `amountToPut` but it is not updated in `usePrepareContractWrite` function above
amountToPut = utils.parseEther(debouncedStakeAmount);
write?.();
};
const putAllToken = async () => {
//This does change the value of `amountToPut` but it is not updated in `usePrepareContractWrite` function above
amountToPut = utils.parseEther(totalTokenAmount.toString());
write?.();
};
return (
<div>
<p>
Submit All token{" "}
{/* Submit all amount, first event */}
<button onClick={putAllToken} disabled={!write || isLoading}>
Submit All Amount
</button>
</p>
<p>
Sumbit partial amount
<input
type="text"
id="partialSubmit"
onChange={(e) => setPartialAmount(e.target.value)}
/>
{/* Submit partial amount, second event */}
<button onClick={putPartialToken} disabled={!write || isLoading}>
Submit Partial Amount
</button>
</p>
</div>
);
};
export default submitToken;
Not sure how to solve this problem so that both button onclick event help to update the argument amountToPut
in usePrepareContractWrite
before calling write?.()
?
Update
I also tried using useRef
hooks. It also didn't work.
const amountToPut = useRef<BigNumber>(BigNumber.from("0"));
const {
config,
error: prepareError,
isError: isPrepareError,
} = usePrepareContractWrite({
address: tokenAddress,
abi: tokenAbi,
functionName: "myWritableFun",
args: [amountToPut.current], // This doesn't update when we change the `partialAmount` in function below
});
const putPartialToken = () => {
if (isNaN(Number(debountAmount))) {
alert("Not a valid amount");
return;
}
// we are checking this in contract too
if (Number(debountAmount) > totalTokenAmount) {
alert("Amount overflow!");
return;
}
amountToPut.current = utils.parseEther(debouncedStakeAmount);
write?.();
};
const putAllToken = async () => {
amountToPut.current = utils.parseEther(totalTokenAmount.toString());
write?.();
};
useContractWrite
and removedusePrepareContractWrite
completely. If you need to perform input data validation, its really hard.