Apologies for that.
Here is the staking code from the smart contract:
function stakeTokens(uint256 _amount, address _token) public nonReentrant {
require(fund_state == FUND_STATE.OPEN);
require(_amount > 0, "Amount must be more than zero!");
require(tokenIsAllowed(_token), "Token is currently not allowed!");
(uint256 price, uint256 decimals) = getTokenValue(_token);
require(
totalRaised + ((_amount * price) / ((10**decimals))) < goal,
"Too much money"
);
IERC20(_token).transferFrom(msg.sender, address(this), _amount);
updateUniqueTokensStaked(msg.sender, _token);
stakingBalance[_token][msg.sender] =
stakingBalance[_token][msg.sender] +
_amount;
if (uniqueTokensStaked[msg.sender] == 1) {
stakers.push(msg.sender);
}
totalRaised = uint256(
totalRaised + ((_amount * price) / ((10**decimals)))
);
}
Here is the code for the form:
export const Fund1Form = ({ token }: StakeFormProps) => {
const { address: tokenAddress, name } = token
const { account } = useEthers()
const tokenBalance = useTokenBalance(tokenAddress, account)
const formattedTokenBalance: number = tokenBalance ? parseFloat(formatUnits(tokenBalance, 18)) : 0
const [amount, setAmount] = useState<number | string | Array<number | string>>(0)
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const newAmount = event.target.value === "" ? "" : Number(event.target.value)
setAmount(newAmount)
console.log(newAmount)
}
const { approveAndStake, approveAndStakeErc20State } = useStakeTokens(tokenAddress)
const handleStakeSubmit = () => {
const amountAsWei = utils.parseEther(amount.toString())
return approveAndStake(amountAsWei.toString())
}
const navigate = useNavigate();
return (
<>
<Box>
<div className="flex flex-1 justify-items-start flex-col md:mt-1 -mx-6">
<div className="p-6 flex flex-1 justify-items-start flex-col md:mt-1 bg-[#D8E1E6] rounded-lg mb-px">
<a className="flex place-content-start font-bold text-[#28282b]">
Investment Amount
</a>
<input
className="my-2 w-full rounded-md p-2 outline-none text-black border-[#000000] border-[1.5px] text-sm h-12"
placeholder="Amount"
step="0.0001"
type="number"
onChange={handleInputChange}
/>
<ButtonUnstyled
onClick={handleStakeSubmit}
className="text-[#28282b] font-bold w-full mt-2 border-[2.5px] p-2 border-[#2952e3] hover:bg-[#5c8193] bg-[#f7f9fa] rounded-full cursor-pointer"
>
INVEST
</ButtonUnstyled>
</div>
</div>
</Box>
</>
)
}
and here is the code for the hook:
export const useStakeTokens = (tokenAddress: string) => {
const { chainId } = useEthers()
console.log({ chainId })
const { abi } = TokenFarm
const tokenFarmAddress = chainId ? networkMapping[String(chainId)]["TokenFarm"][0] : constants.AddressZero
console.log(tokenFarmAddress)
const tokenFarmInterface = new utils.Interface(abi)
const tokenFarmContract = new Contract(tokenFarmAddress, tokenFarmInterface)
const erc20ABI = ERC20.abi
const erc20Interface = new utils.Interface(erc20ABI)
const erc20Contract = new Contract(tokenAddress, erc20Interface)
const { send: approveErc20Send, state: approveAndStakeErc20State } =
useContractFunction(erc20Contract, "approve", {
transactionName: "Approve ERC20 transfer",
})
const approveAndStake = (amount: string) => {
setAmountToStake(amount)
return approveErc20Send(tokenFarmAddress, amount)
}
const { send: stakeSend, state: stakeState } =
useContractFunction(tokenFarmContract, "stakeTokens", {
transactionName: "Stake Tokens",
})
const [amountToStake, setAmountToStake] = useState("0")
useEffect(() => {
if (approveAndStakeErc20State.status === "Success") {
stakeSend(amountToStake, tokenAddress);
}
}, [approveAndStakeErc20State])
const [state, setState] = useState(approveAndStakeErc20State)
return { approveAndStake, approveErc20Send }
}
For reference, I took heavy inspiration from FreeCodeCamp's 16 hour solidity tutorial with Patrick Collins