Trying to incorporate 1Inch

Hey, i’ve been struggling to find out what I’m doing wrong here. followed Ivan’s video on doing a swap and trying to port that code over to React, but issues. I did a console.log and can see 1inch plugin is loaded. This line, “dex = Moralis.Plugins.oneInch” doesnt appear to be a thing anymore… I was able to get metamask to pop up using a small hardcoded send value of “0.01” Number(Moralis.Units.ETH(“0.01”)) will this conversion be the same for BEP20.
if someone could help a paid customer out that’d be great. i have redacted my token name from the code, it is active and does have liquidity.

**edit so I am able to get a successful transaction but it is not right compared to the token value I put in i get errors when i try using my variable in place of the “0.01” but if i use a small number like in the tutorial example it seems to work i put 0.05 in hit submit and it sent me 560 of my tokens valued around $3.70. if i try and buy 1.0 i get promise error in console…
Screenshot_28

import "./swap.scss";
import { useState, useEffect } from "react";
import { Form, InputNumber, Button, Statistic } from "antd";
import {
  useWeb3ExecuteFunction,
  useNativeBalance,
  useMoralis,
} from "react-moralis";

import { optionsgetbalance } from "../../cakeABI";

const Swapper = () => {
  const { Moralis, isWeb3Enabled, enableWeb3, isAuthenticated, isWeb3EnableLoading } =
    useMoralis();

  const [cake, setcake] = useState();
  const [bnbprice, setbnb] = useState();
  const { data: indBal, fetch: fetchindBal } = useWeb3ExecuteFunction();
  const { data: balanceNative } = useNativeBalance();

  const RenderSwapBalances = async () => {
    let currentUser = Object.keys(localStorage).filter((o) =>
      o.includes("currentUser")
    )[0];

    // eslint-disable-next-line
    let res3 = await fetchindBal({
      params: {
        ...optionsgetbalance,
        params: {
          who: JSON.parse(
            JSON.parse(JSON.stringify(localStorage.getItem(currentUser)))
          ).ethAddress,
        },
      },
    });
    let res5 = await fetch(
      "https://api.pancakeswap.info/api/v2/tokens/0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"
    );
    setbnb(await res5.json());

    let res4 = await fetch(
      "https://api.pancakeswap.info/api/v2/tokens/0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82"
    );

    setcake(await res4.json());
  };

  useEffect(() => {
    if (isAuthenticated && !isWeb3Enabled && !isWeb3EnableLoading) {
      const connectorId = window.localStorage.getItem("connectorId");
      enableWeb3({ provider: connectorId });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isAuthenticated, isWeb3Enabled]);

  useEffect(() => {
    if (isAuthenticated && isWeb3Enabled) {
        Moralis.initPlugins();
        RenderSwapBalances();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isAuthenticated, isWeb3Enabled]);


  let dex;
  dex = Moralis.Plugins.oneInch; // not working anymore?

  async function DoSwap(values) {
    const cakeAmt = values.cakebuyamt;
    const options = {
        chain: "bsc", // The blockchain you want to use (eth/bsc/polygon)
        fromTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // The token you want to swap
        toTokenAddress: "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82", // The token you want to receive
        amount: Number(Moralis.Units.ETH(cakeAmt)),
        fromAddress: Moralis.User.current().get("ethAddress"), // Your wallet address
        slippage: 1,
      };
      
    var receipt = await dex.swap(options)
    console.log(receipt);
  }


  const [form] = Form.useForm();
  return (
    <div className="swapContainer">
      <div className="showBalance">
        <div>
          <Statistic
            title={<span>cake Price</span>}
            valueStyle={{ fontFamily: "bank gothic", fontWeight: "bold" }}
            value={cake?.data?.price}
            precision={6}
            prefix="$"
          />
        </div>

        <div>
          <Statistic
            title={<span>cake Balance</span>}
            valueStyle={{ fontFamily: "bank gothic", fontWeight: "bold" }}
            value={
              indBal &&
              parseInt(JSON.parse(JSON.stringify(indBal)).hex, 16) /
                Math.pow(10, 18)
            }
            precision={2}
          />
        </div>
        <div>
          <Statistic
            title={<span>BNB Balance</span>}
            valueStyle={{ fontFamily: "bank gothic", fontWeight: "bold" }}
            value={
              balanceNative.balance &&
              parseInt(JSON.parse(JSON.stringify(balanceNative.balance))) /
                Math.pow(10, 18)
            }
            precision={6}
          />
        </div>
      </div>
      <div className="buycake">BUY cake</div>
      <div className="swapForm">
        <Form
          form={form}
          autoComplete="off"
          onFinish={(values) => DoSwap(values)}
          onFinishFailed={(error) => {
            console.log({ error });
          }}
        >

          <Form.Item
            name="cakebuyamt"
            rules={[
              {
                required: true,
              },
            ]}
          >
            <InputNumber
              prefix="cake -   "
              style={{
                width: 200,
              }}
              min="0"
              max="22000"
              step="1.000000"
              stringMode
            />
          </Form.Item>
          <Form.Item>
            <Button type="primary" htmlType="submit">
              Swap
            </Button>
          </Form.Item>
        </Form>

      </div>
    </div>
  );
};

export default Swapper;

@YoloGuy
Firstly you can try

GetQoute function to know the exact amount of tokens you are suppose to get in return

async function getQuote() {
  const quote = await Moralis.Plugins.oneInch.quote({
    chain: 'bsc', // The blockchain you want to use (eth/bsc/polygon)
    fromTokenAddress: '0x0da6ed8b13214ff28e9ca979dd37439e8a88f6c4', // The token you want to swap
    toTokenAddress: '0x6fd7c98458a943f469e1cf4ea85b173f5cd342f4', // The token you want to receive
    amount: '1000',
  });
  console.log(quote);
}

Also for buying token you need to Approve the token first

async function approve() {
  await Moralis.Plugins.oneInch.approve({
    chain: 'bsc', // The blockchain you want to use (eth/bsc/polygon)
    tokenAddress: '0x0da6ed8b13214ff28e9ca979dd37439e8a88f6c4', // The token you want to swap
    fromAddress: '0x6217e65d864d77DEcbFF0CFeFA13A93f7C1dD064', // Your wallet address
  });
}

Check link for more info: https://moralis.io/plugins/1inch/

2 Likes

Ok thats useful thanks man! kinda wish the video tutorial would explain this part … he just says that’s it… swap function go! one line of code! Anyways… my dumb head realizes that the reason why it sent me wrong token amount was because in the swap options the amount is in BNB … duh. ok starting to get it except … why was it able to send without approval? how does that work? a little guidance into how I should implement approval into my form maybe? form onFinish call approve then call doswap right after? error handling?

ok so its asking for bnb amount (from address) so i run the getQuote command and i do get quotes for 2bnb or 1000bnb vs my token, but not 1bnb or any amount under that… whats up ? with regards to approval how would we handle the submit button? I just want to build a simple swapper that only swaps a hard coded token. and I know many others want this too, so lets get it, almost halfway there.

@YoloGuy, you can also read more about it here https://github.com/MoralisWeb3/react-moralis#dex-plugin-hooks using the react hook. Same way as @taha mentioned, but a react way

1 Like

Hey, thanks for the help. If anyone can help a man figure out how to use approve properly in a form that’d be wicked. There’s a couple things id like to know , one, using approve button and disabling it after completing, two, disabling swap button after swap until receipt. And if anyone knows how to push the quotes into form fields that’d be great too.

You can check the approve/allowance status and show/hide an Approve button based on that. And add a disabled to your buttons based on the loading state e.g. isLoading from useWeb3ExecuteFunction.

hmm okay, i am able to approve with this code:


  async function approve() {
    await Moralis.Plugins.oneInch.approve({
      chain: 'bsc', // The blockchain you want to use (eth/bsc/polygon)
      tokenAddress: '0x0da6ed8b13214ff28e9ca979dd37439e8a88f6c4', // The token you want to swap
      fromAddress: Moralis.User.current().get("ethAddress"),  // Your wallet address
    });
  }

but your saying i need to execute a contract function to watch approve status? which function? i cant find anything on approval in moralis react github page sorry for newb questions, just kinda hard to find examples of implementation, especially for reactjs.

do i just add this inside

`  const { data, error, fetch, isFetching, isLoading } = useWeb3ExecuteFunction();
`

does that not require abi and a function name?

You can check the allowance function on the contract (I could be mistaken if oneInch’s approve is actually doing something else). But the plugin has hasAllowance for this.

Yes useWeb3ExecuteFunction requires ABI and function name. I noticed it in your code but I see now you haven’t actually used it yet. You can use Moralis.Plugins.oneInch.swap instead.

Looks like the plugin has everything you need.

1 Like

Yeah i was using useWeb3ExecuteFunction before to grab other token data not related. I’ve been assuming hasAllowance is just a check of spendable “from” balance, is it something else? how is that related to cheking if approved or not? is approval only needed when selling tokens for native? I’m confused as to why i’m able to buy and it works without any approval? Theres gotta be a simple check or arrow function i can put into the button component to enable and disable based on approval/allowance boolean, that info is definitely not on that oneInch plugin page. I need to study up my JS, definitely over my head a bit , at least its fun :wink: guess im looking for an approve function in abi then?

Yes hasAllowance just checks the approved spending amount.

No, approve is not required for buying, that’s just a regular transaction. Your “approval” is you signing the transaction. For swaps, read this.

For an enabled/disabled state, a basic implementation is using useState and use that for the disabled property on your button. When the user clicks approve or swap, set it to true which disables it, and then set it to false after a oneInch await.

alright, i’ve opted to go without the approve button and just check in the code, so the code below is what i’ve been trying to use to get the swapper to sell tokens for bnb, it seems to get past allowance and approval check but Error 400 on swap after popping up swap complete. :sweat_smile:

  async function trySwap(fromTokenAddr, toTokenAddr, values) {
    const address = Moralis.User.current().get("ethAddress");
    console.log("from address:", fromTokenAddr);
    const amount = Moralis.Units.Token(values.tokenSellAmt).toString(); //change
    console.log("amount:", amount);
    if (fromTokenAddr !== "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") {
      const allowance = await Moralis.Plugins.oneInch.hasAllowance({
        chain: "bsc", // The blockchain you want to use (eth/bsc/polygon)
        fromTokenAddress: fromTokenAddr, // The token you want to swap
        fromAddress: address, // Your wallet address
        amount: amount,
      });
      console.log("user has enough balance:", allowance);

      if (!allowance) {
        await Moralis.Plugins.oneInch.approve({
          chain: "bsc", // The blockchain you want to use (eth/bsc/polygon)
          tokenAddress: fromTokenAddr, // The token you want to swap
          fromAddress: address, // Your wallet address
        });
      }
    }

    try {
      doSwap(fromTokenAddr, toTokenAddr, address, amount)
      alert("Swap Complete");
    } catch (error) {
      console.log(error);
      alert("Insufficient Balance");
    }
  }

  async function doSwap(fromTokenAddr, toTokenAddr, userAddress, amount) {
    const receipt = await Moralis.Plugins.oneInch.swap({
      chain: 'bsc', // The blockchain you want to use (eth/bsc/polygon)
      fromTokenAddress: fromTokenAddr, // The token you want to swap
      toTokenAddress: toTokenAddr, // The token you want to receive
      amount: amount,
      fromAddress: userAddress, // Your wallet address
      slippage: 15,
    });
    console.log(receipt);
  }

Are you getting the receipt logged from doSwap? Must be something wrong with your options.

The swap complete message won’t really matter because it will run even with errors.

no receipt, it doesn’t get that far. seems to be a parsing error, I tried this code variation and same thing basically, ParseError: 141 [object Object].

  async function trySwap(fromTokenAddr, toTokenAddr, values) {
    const pluginList = Moralis.Plugins;
     console.log(pluginList);
    const address = Moralis.User.current().get("ethAddress");
    const amount = Moralis.Units.Token(values.tokenSellAmt).toString(); 
    console.log("amount:", amount);
    if (fromTokenAddr !== "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") {
      await Moralis.Plugins.oneInch
        .hasAllowance({
          chain: 'bsc', // The blockchain you want to use (eth/bsc/polygon)
          fromTokenAddress: fromTokenAddr, // The token you want to swap
          fromAddress: address, // Your wallet address
          amount,
        })
        .then(async (allowance) => {
          console.log(allowance);
          if (!allowance) {
            await Moralis.Plugins.oneInch.approve({
              chain: 'bsc', // The blockchain you want to use (eth/bsc/polygon)
              tokenAddress: fromTokenAddr, // The token you want to swap
              fromAddress: address, // Your wallet address
            });
          }
        })
        .catch((e) => alert(e.message));

    }

    
      await doSwap(fromTokenAddr, toTokenAddr, address, amount)
      .then((receipt) => {
        console.log("receipt status code: ", receipt);
        if (receipt.statusCode !== 400) {
          alert("Swap Complete");
          setTimeout(() => {
            window.location.reload("/");
          }, 500);
        }
        // else {
        //   alert("Receipt - Not enough balance!");
        // }
      })
      .catch((e) => {
        console.log("error: ", e);
        alert(e);
      });
  
  }

  async function doSwap(fromTokenAddr, toTokenAddr, userAddress, amount) {
    return await Moralis.Plugins.oneInch.swap({
      chain: 'bsc', // The blockchain you want to use (eth/bsc/polygon)
      fromTokenAddress: fromTokenAddr, // The token you want to swap
      toTokenAddress: toTokenAddr, // The token you want to receive
      amount: Moralis.Units.Token(amount).toString(),
      fromAddress: userAddress, // Your wallet address
      slippage: 15,
    });
  }

i was able to buy with BNB before with this doswap function, tried both somthing else changed. not sure what?

  async function doSwap(fromTokenAddr, toTokenAddr, userAddress, amount) {
    const options = {
      chain: "bsc", // The blockchain you want to use (eth/bsc/polygon)
      fromTokenAddress: fromTokenAddr, // The token you want to swap
      toTokenAddress: toTokenAddr, // The token you want to receive
      amount: amount,
      fromAddress: userAddress, // Your wallet address
      slippage: 15,
    };
    var receipt = await dex.swap(options)
    console.log(receipt);

  }

Can you try the swap with static values that roughly match what you’re doing now? And log each variable you’re using (fromTokenAddr, toTokenAddr, etc.) separately to make sure everything is correct and in the right format - it looks like all parameters for swap should be a string except for slippage.

okay, I tried changing to static values and ended up in a loop with swap complete alert, and the same Promise Object error. then I realized that that error was popping up before when I enter values into my form fields, where it gets quotes… in a very amateur way I’m sure … it’s some serious witchcraft and I know there’s got to be a better way but I have two antd form fields one for bnb and one for token and two onchange handlers that each call a quote, oh yeah and two different quote functions… lol. In the contract there is a max buy and max sell so i have it so the fields automatically adjust each other and the token amount is limited to 22000 and the bnbquote is run again to match. This setup was working before when i was buying tokens with bnb, but starting to think the problem may lie here…

sorry I know this chunk of code is confusing :man_facepalming:

  function onTokenAmtUpdate(value) {
    getQuotebnb(tokenContractAddr, bnbContractAddr, value);

    console.log("Token amount changed", value);
  }
  function onBnbAmtUpdate(value) {
    getQuoteToken(bnbContractAddr, tokenContractAddr, value);
  }

async function getQuoteToken(fromTokenAddr, toTokenAddr, amt) {
    const quote = await Moralis.Plugins.oneInch.quote({
      chain: "bsc", // The blockchain you want to use (eth/bsc/polygon)
      fromTokenAddress: fromTokenAddr, // The token you want to swap
      toTokenAddress: toTokenAddr, // The token you want to receive
      amount: Moralis.Units.Token(amt, 18),
    });
    console.log("from:", Moralis.Units.FromWei(quote.fromTokenAmount));
    console.log("to: ", Moralis.Units.FromWei(quote.toTokenAmount));
    // if toTokenAmount > 22000 then set tokensellamt to 22000 else
    if (Moralis.Units.FromWei(quote.toTokenAmount) > 22000) {
      form.setFieldsValue({ tokenSellAmt: 22000 });
      getQuotebnb(toTokenAddr, fromTokenAddr, 22000);
    } else {
      form.setFieldsValue({
        tokenSellAmt: Moralis.Units.FromWei(quote.toTokenAmount),
      });
    }
    console.log(quote);

    document.getElementById("gas-est").innerHTML = quote.estimatedGas;
  }

  async function getQuotebnb(fromTokenAddr, toTokenAddr, amt) {
    const quote = await Moralis.Plugins.oneInch.quote({
      chain: "bsc", // The blockchain you want to use (eth/bsc/polygon)
      fromTokenAddress: fromTokenAddr, // The token you want to swap
      toTokenAddress: toTokenAddr, // The token you want to receive
      amount: Moralis.Units.Token(amt, 18),
    });
    console.log("from:", Moralis.Units.FromWei(quote.fromTokenAmount));
    console.log("to: ", Moralis.Units.FromWei(quote.toTokenAmount));
    form.setFieldsValue({
      costbnb: Moralis.Units.FromWei(quote.toTokenAmount),
    });
  }

This is what I’m seeing under sources when I click on the error code reference, i tried wrapping the values in JSON.parse(JSON.stringify( )); but diddnt change anything. This is the response from the server.
{"result":{"status":200,"data":{"success":true,"result":{"error":422,"message":"Missing parameters"}}}}
Screenshot_37

Can you share a generic repo (take out all sensitive details)? That would make it easier to work with. Since it was working before have a look at anything you’re doing differently.

Yeah I’ll see if I can make an easy runnable example, i have to get on github. I think the issue may be that the first variable into trySwap(tokenContractAddr, tokenSellAmt, "bsc") might need to be a list of address and token decimals. That’s what it seems to want in useOneInch.js hook code anyway, going to look at that later today

How are you getting on with some of these (and the other disconnect wallet issue)? If you’re still having issues, can you get those repo(s) up?