All transactions sent are duplicated

As the title says, every transaction I send through the window.ethereum object injected by MetaMask is duplicated. Currently I am trying to send one transaction to set the token allowance for a swap and then one to perform the swap. Under both instances MetaMask prompts the user to approve 4 transactions (two of each of the ones I am trying to perform). I’ve narrowed it down to being the web3 methods, as when I paste the methods twice I’ll end up getting eight transactions. Could anyone help me with this issue? Also I am using the 0x API for sourcing liquidity, so that is what the getQuote method is for.

 async function swap() {
    const web3access = new Web3(window.ethereum)
    const abi = [{ "inputs": [ { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "string", "name": "symbol", "type": "string" }, { "internalType": "uint256", "name": "max_supply", "type": "uint256" } ], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" } ], "name": "allowance", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "approve", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" } ], "name": "balanceOf", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "burn", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "burnFrom", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "decimals", "outputs": [ { "internalType": "uint8", "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "subtractedValue", "type": "uint256" } ], "name": "decreaseAllowance", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "addedValue", "type": "uint256" } ], "name": "increaseAllowance", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "name", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "totalSupply", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transfer", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "sender", "type": "address" }, { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transferFrom", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }];
    const maxApproval = "10000000000000000000000000000000000"; 
    console.log(maxApproval);
    const contract = new web3access.eth.Contract(abi, sellToken);
    const account = await accountPromise;
    let allowanceQuote = await getQuote(true);
    let swapQuote = await getQuote(false);
    allowanceQuote.onreadystatechange = (e) => { //Maybe should check if user has already set approval for sellToken passed in above depending on whether or not I decide to have users set unlimited token allowances per token approval.
        let responseDict = JSON.parse(allowanceQuote.responseText)
        contract.methods.approve(responseDict["allowanceTarget"], maxApproval).send({from: account}).then(tx => { //Token approval method for 0x api contract address
        console.log(tx);
        });
    };
    swapQuote.onreadystatechange = (e) => { //Need this to run AFTER a response from the above approve method returns a successful transaction.
        let responseDict = JSON.parse(swapQuote.responseText)
        console.log(web3access.eth.sendTransaction(responseDict));
    }
}
2 Likes

Hi @parkerb2001 ,

Have you been able to look through the MetaMask docs?

1 Like

I have, I’m not sure if I see a solution as I’m calling the sendTransaction method only as needed in a similar regard as outlined in the docs.

2 Likes

Hello @parkerb2001

Do you have two pop-ups with signing the transaction, or two pop-up windows - in the first approving, and in the second signing the transaction?

5 Likes

I have four actually total. Two windows for the approval and two for signing the transaction. I am trying to have only two total pop up, one for the approval and one for the signing.

do you have one browser installed, with one instance of the MetaMask extension?

3 Likes

I have more than one browser on my computer but only google chrome (and only one profile instance) has MetaMask installed as an extension

This is what happens when I call the token allowance transaction through MetaMask with:

allowanceQuote.onreadystatechange = (e) => { //Maybe should check if user has already set approval for sellToken passed in above depending on whether or not I decide to have users set unlimited token allowances per token approval. let responseDict = JSON.parse(allowanceQuote.responseText) contract.methods.approve(responseDict["allowanceTarget"], maxApproval).send({from: account}).then(tx => { //Token approval method for 0x api contract address console.log(tx); }); };

See the below screenshots:

imgur(dot)com/a/Jjt3nXy

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.