import { useWeb3Contract } from "react-moralis"
import {
wethAbi,
wethAddress,
mutualsAbi,
mutualsAddress,
achieverAbi,
achieverAddress,
} from "../../constants"
import { Form } from "web3uikit"
import { ethers } from "ethers"
import { useState } from "react"
export default function MutualsSwapForm() {
const { runContractFunction } = useWeb3Contract()
let achieverApproveOptions = {
abi: achieverAbi,
contractAddress: achieverAddress,
functionName: "approve",
}
let wethApproveOptions = {
abi: wethAbi,
contractAddress: wethAddress,
functionName: "approve",
}
let swapOptions = {
abi: mutualsAbi,
contractAddress: mutualsAddress,
functionName: "swap",
}
const [swapResult, setSwapResult] = useState("0")
const { runContractFunction: getReserve0 } = useWeb3Contract({
abi: mutualsAbi,
contractAddress: mutualsAddress,
functionName: "reserve0",
params: {},
})
const { runContractFunction: getReserve1 } = useWeb3Contract({
abi: mutualsAbi,
contractAddress: mutualsAddress,
functionName: "reserve1",
params: {},
})
async function handleSwapSubmit(data) {
console.table({ data })
let selectVal = document.querySelector("#swap-form select").value
let approveOptions
const amountToApprove = document.querySelector("#input_1").value
if (selectVal == "WETH") {
wethApproveOptions.params = {
wad: ethers.utils.parseUnits(amountToApprove, "ether").toString(),
guy: mutualsAddress,
}
approveOptions = wethApproveOptions
} else {
achieverApproveOptions.params = {
amount: ethers.utils.parseUnits(amountToApprove, "ether").toString(),
spender: mutualsAddress,
}
approveOptions = achieverApproveOptions
}
console.log("Approving...")
console.log(approveOptions, "a")
const tx = await runContractFunction({
params: approveOptions,
onError: (error) => console.log(error),
onSuccess: () => {
handleApproveSuccess(
approveOptions.contractAddress,
ethers.utils.parseUnits(amountToApprove, "ether").toString()
)
},
})
}
async function handleApproveSuccess(contractAddress, amountToSwapFormatted) {
swapOptions.params = {
_amountIn: amountToSwapFormatted,
_tokenIn: contractAddress,
}
console.log({ swapOptions })
console.log(`Swapping ${swapOptions.params._amountIn} ...`)
const tx = await runContractFunction({
params: swapOptions,
onError: (error) => console.log(error),
})
console.log({ tx })
await tx.wait(1)
console.log("Transaction has confirmed by 1 block")
}
async function handleSwapChanged(data) {
if (data.target.tagName == "SELECT") {
let swapAmount = document.querySelector("label[for=input_1]")
swapAmount.textContent = `Amount to swap (in ${data.target.value})`
} else {
let tokenSelected = document.querySelector("#swap-form select").value
let array =
tokenSelected == "WETH"
? [
ethers.utils.formatEther(
await getReserve0({ onError: (error) => console.log(error) })
),
ethers.utils.formatEther(
await getReserve1({ onError: (error) => console.log(error) })
),
]
: [
ethers.utils.formatEther(
await getReserve1({ onError: (error) => console.log(error) })
),
ethers.utils.formatEther(
await getReserve0({ onError: (error) => console.log(error) })
),
]
// console.log(await getReserve0())
let [reserveIn, reserveOut] = array
let amountInWithFee = (data.target.value * 997) / 1000
let amountOut = (+reserveOut * amountInWithFee) / (+reserveIn + amountInWithFee)
setSwapResult(amountOut)
}
}
return (
<div className="shadow-2xl rounded-xl p-4">
<Form
onSubmit={handleSwapSubmit}
onChange={handleSwapChanged}
id="swap-form"
data={[
{
selectOptions: [
{
id: "ACH",
label: "ACH",
},
{
id: "WETH",
label: "WETH",
},
],
name: "Select token to swap",
type: "select",
value: "",
},
{
inputWidth: "50%",
name: "Amount to swap",
type: "number",
value: "",
key: "amountToSwap",
validation: { required: true },
},
{
value: `Corresponding Token Out: ${swapResult}`,
type: "box",
key: "swap-result",
},
]}
title="Let's swap!"
></Form>
</div>
)
}
Whenever this swap button was submitted, the approve function would always need to invoke at least twice before the onSuccess could bring you to the swap function. On the first approve, the following error will be thrown on my console:
Object
MutualsSwapForm.js?2915:69 Approving...
MutualsSwapForm.js?2915:70
{abi: Array(16), contractAddress: '0xc778417E063141139Fce010982780140Aa0cD5Ab', functionName: 'approve', params: {…}}
'a'
MutualsSwapForm.js?2915:88
{swapOptions: {…}}
MutualsSwapForm.js?2915:89 Swapping 25000000000000000 ...
inpage.js:1 MetaMask - RPC Error: execution reverted
{code: -32000, message: 'execution reverted'}
MutualsSwapForm.js?2915:92 Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (error={"code":-32000,"message":"execution reverted"}, method="estimateGas", transaction={"from":"0x8C6bB2BD30f4e28dCD0f6faF6B2d315f67155Abc","to":"0xb41fBe2e34700Eea625204c172d050dAF1EDc14D","data":"0xd004f0f7000000000000000000000000c778417e063141139fce010982780140aa0cd5ab0000000000000000000000000000000000000000000000000058d15e17628000","accessList":null}, code=UNPREDICTABLE_GAS_LIMIT, version=providers/5.6.0)
at Logger.makeError (index.js?dd68:219:1)
at Logger.throwError (index.js?dd68:228:1)
at checkError (json-rpc-provider.js?8679:73:1)
at Web3Provider.eval (json-rpc-provider.js?8679:490:1)
at Generator.throw (<anonymous>)
at rejected (json-rpc-provider.js?8679:6:42)
MutualsSwapForm.js?2915:94
{tx: undefined}
MutualsSwapForm.js?2915:95 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'wait')
at _callee$ (MutualsSwapForm.js?2915:95:18)
at tryCatch (runtime.js?ecd4:45:16)
at Generator.invoke [as _invoke] (runtime.js?ecd4:274:1)
at prototype.<computed> [as next] (runtime.js?ecd4:97:1)
at asyncGeneratorStep (MutualsSwapForm.js?2915:1:1)
at _next (MutualsSwapForm.js?2915:1:1)
client.js?374c:7 [Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive. See https://www.chromestatus.com/feature/5745543795965952
At first, I thought this could be the gas issue. But then I realized the approve operation actually went successful on the etherscan and also on the Metamask. And usually, refreshing the page and re-entering the same input and resubmitting the form would make the two-step transaction (approve, swap) go through smoothly:
Object
MutualsSwapForm.js?2915:69 Approving...
MutualsSwapForm.js?2915:70
{abi: Array(16), contractAddress: '0xc778417E063141139Fce010982780140Aa0cD5Ab', functionName: 'approve', params: {…}}
'a'
MutualsSwapForm.js?2915:88
{swapOptions: {…}}
MutualsSwapForm.js?2915:89 Swapping 25000000000000000 ...
MutualsSwapForm.js?2915:94
{tx: {…}}
MutualsSwapForm.js?2915:96 Transaction has confirmed by 1 block
Increasing gas limit on the approve method will not change the above pattern of operation. Could anyone help look into this issue? Thanks.