religion-counter / onlyone

DeFi future without taxes
78 stars 44 forks source link

Selling Tokens on PancakeSwap #2

Open marcichan opened 3 years ago

marcichan commented 3 years ago

Hey, I tried your examples for buying tokens on PancakeSwap. Everything works fine. Now Im trying to sell tokens and I cant get it to work. Could you maybe make an example for that too, or give me some tips? Thanks!

religion-counter commented 3 years ago

I will upload a sell example Tomorrow. Regards

religion-counter commented 3 years ago

I have uploaded the sell script: https://github.com/religion-counter/onlyone/blob/main/helper-scripts/sell-onlyone-pancakeswap.js In order to sell you need to first approve the token for selling. This is the approve transaction executed by the script: https://bscscan.com/tx/0x5c87de77a431ced21532d1f10512d0cfd3ec4871f37effb83f62d6e6cd341772 And this is the actual sell again executed by the script: https://bscscan.com/tx/0x7faa7289646526a33e5ee5b46d4cb228d1aca87ec174c7c65679f9c43e2ecb3c I also did many failed attempts like here: https://bscscan.com/tx/0x68df97ff5e9b17566d0dd5345558979609ddc55bfd71a0c494741ac870040307 and this address: https://bscscan.com/address/0xD41FeE0d3f057C01F831ECf31ddC9ef082ADe078 because I tried to sell without approving first :)

marcichan commented 3 years ago

Thank you alot! I was able to get it done late in the night, too :D

religion-counter commented 3 years ago

I am glad to hear that you were able to get it done. Our mission is to educate more people about what is going on behind the crypto scene ;).

marcichan commented 3 years ago

Do you know what's the problem with this error? https://bscscan.com/tx/0x7158bb87094da67e90c0afe934b36a7bed37c0085925d01790f46556b1bb91b7

religion-counter commented 3 years ago

You have to see whether the token you are trying to sell is approved for sell on the router. Also you can try to manually sell via the pancakeswap website and then copy the same transaction data.

sircovsw commented 3 years ago

I have an error when selling. Amount as in your example. (node:19916) UnhandledPromiseRejectionWarning: Error: Transaction has been reverted by the EVM:

approve: https://bscscan.com/tx/0x39968ba83f35b2efaa654542e6695d7f9d50f6173b8dcb3b5e932c34ed6223b8 sell: https://bscscan.com/tx/0xfe25959a337bc31d4d0900cd055db2b6cda7a2cde4557c8225d224b4e0d0a3ab

Besides that, I have problems:

There are no problems with the purchase. Thanks for your script.

religion-counter commented 3 years ago

I have an error when selling. Amount as in your example. (node:19916) UnhandledPromiseRejectionWarning: Error: Transaction has been reverted by the EVM:

approve: https://bscscan.com/tx/0x39968ba83f35b2efaa654542e6695d7f9d50f6173b8dcb3b5e932c34ed6223b8 sell: https://bscscan.com/tx/0xfe25959a337bc31d4d0900cd055db2b6cda7a2cde4557c8225d224b4e0d0a3ab

Besides that, I have problems:

* how to determine the balance of a coin. In the wallet of coins: 150382.500540337410654784. The script outputs 150382500540337410654784. I don't understand how to format.

* how to correctly transfer the balance of the coin to the sale method

There are no problems with the purchase. Thanks for your script.

Hi sircovsw,

The balance is the number of coins multiplied by the number of decimals. For your use case 150382.500540337410654784 has 18 decimals. For your example (https://bscscan.com/tx/0xfe25959a337bc31d4d0900cd055db2b6cda7a2cde4557c8225d224b4e0d0a3ab) you have input 10000000000 UDOGE and want to receive 5400000000000 BNB for that. You can try to set amountOutMin to 10 or something small (which is something like sell on market price) and see whether the transaction will succeed then.

religion-counter commented 3 years ago

With the following script I was able to sell UDOGE for ONLYONE: https://bscscan.com/tx/0xa1695466014badc14265c577d5310cf2bd9c59a411d8930659d42cae6c9751c5 Please note that if you want to swap tokens for BNB you should call swapExactTokensForETHSupportingFeeOnTransferTokens and if you want to swap tokens for other tokens you should call swapExactTokensForTokensSupportingFeeOnTransferTokens Note that UDOGE gas 9 decimals so I multiply the original amount by 1e9: amountToSell*1e9

// Sells UDOGE for ONLYONE from pancakeswap for address ${targetAccounts[targetIndex].address}

var fs = require('fs')
var Tx = require('ethereumjs-tx').Transaction;
var Web3 = require('web3')
var Common = require('ethereumjs-common').default;

var web3 = new Web3(new Web3.providers.HttpProvider('https://bsc-dataseed.binance.org/'))
var BSC_FORK = Common.forCustomChain(
    'mainnet',
    {
        name: 'Binance Smart Chain Mainnet',
        networkId: 56,
        chainId: 56,
        url: 'https://bsc-dataseed.binance.org/'
    },
    'istanbul',
);

var targetAccounts = JSON.parse(fs.readFileSync('account-sell-udoge.json', 'utf-8'));

sellMulty();

async function sellMulty() {
    for (var i = 0; i < 1; ++i) {
        var targetAccount = targetAccounts[i];
        var amountToSell = 300012754.293006283; // Amount you want to sell
        var res = sell(targetAccount, amountToSell*1e9)
            .catch(e => {
                console.error("Error in sell:", e);
                process.exit(1);
            });
        console.log(res);
    }
}

async function sell(targetAccount, amount) {

    var amountToSell = web3.utils.toHex(amount);
    var privateKey = Buffer.from(targetAccount.privateKey.slice(2), 'hex')  ;

    var tokenAddress = '0xd2618bc9c9cdc40ff19e200a7d14a09799c0a152'; // UDOGE contract address
    var WBNBAddress = '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c'; // WBNB token address
    var pancakeSwapRouterAddress = '0x10ed43c718714eb63d5aa57b78b54704e256024e';

    var routerAbi = JSON.parse(fs.readFileSync('pancake-router-abi.json', 'utf-8'));
    var contract = new web3.eth.Contract(routerAbi, pancakeSwapRouterAddress, {from: targetAccount.address});
    var data = contract.methods.swapExactTokensForTokensSupportingFeeOnTransferTokens(
        amountToSell,
        1,
        [tokenAddress,
         WBNBAddress,
         '0xb899db682e6d6164d885ff67c1e676141deaaa40'
        ],
        targetAccount.address,
        web3.utils.toHex(Math.round(Date.now()/1000)+60*20),
    );

    count = await web3.eth.getTransactionCount(targetAccount.address);
    var rawTransaction = {
        "from":targetAccount.address,
        "gasPrice":web3.utils.toHex(5000000000),
        "gasLimit":web3.utils.toHex(460000),
        "to":pancakeSwapRouterAddress,
        "value":web3.utils.toHex(0),
        "data":data.encodeABI(),
        "nonce":web3.utils.toHex(count)
    };

    var transaction = new Tx(rawTransaction, { 'common': BSC_FORK });
    transaction.sign(privateKey);

    var result = await web3.eth.sendSignedTransaction('0x' + transaction.serialize().toString('hex'));
    console.log(result)
    return result;
}

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
} 
sircovsw commented 3 years ago

var amountToSell = 300012754.293006283

Where did you get the value of the variable var amountToSell = 300012754.293006283 ?

Please tell me an example code to get 150382.500540337410654784 from 150382500540337410654784 or 93200875.137806421 from 93200875137806421

sircovsw commented 3 years ago

Please tell me an example code to get 150382.500540337410654784 from 150382500540337410654784 or 93200875.137806421 from 93200875137806421

Handled it

getTokenBalance = async (tokenAddress) => {
        let contractBuyToken = new this.web3.eth.Contract(this.tokenAbi, tokenAddress, {from: this.myContract})
        let balance = await contractBuyToken.methods.balanceOf(this.myContract).call()
        let tokenDecimals = await this.getTokenDecimals(tokenAddress)
        let unit = 'gwei'
        if (parseInt(tokenDecimals) === 18) {
            unit = 'ether'
        }
        balance = this.web3.utils.fromWei(balance, unit)
        return balance
    }
sircovsw commented 3 years ago

var res = sell(targetAccount, amountToSell*1e9) ... var amountToSell = web3.utils.toHex(amount);

if tokenDecimals is 18, then it does not work:

Error: Error: [number-to-bn] while converting number 1.5038250054033741e+23 to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. Given value: "1.5038250054033741e+23"

        let tokenDecimals = await this.getTokenDecimals(tokenAddress)
        let unit = 1e9
        let unit1 = 'gwei'
        if (parseInt(tokenDecimals) === 18) {
            unit = 1e18
            unit1 = 'ether'
        }

        amount = amount * unit;
        console.log(Math.floor(Date.now() / 1000), ' - ', 'amount', amount)

        let amountToSell = this.web3.utils.toHex(amount);
        console.log(Math.floor(Date.now() / 1000), ' - ', 'amountToSell', amountToSell)
religion-counter commented 3 years ago

var res = sell(targetAccount, amountToSell*1e9) ... var amountToSell = web3.utils.toHex(amount);

if tokenDecimals is 18, then it does not work:

Error: Error: [number-to-bn] while converting number 1.5038250054033741e+23 to BN.js instance, error: invalid number value. Value must be an integer, hex string, BN or BigNumber instance. Note, decimals are not supported. Given value: "1.5038250054033741e+23"

        let tokenDecimals = await this.getTokenDecimals(tokenAddress)
        let unit = 1e9
        let unit1 = 'gwei'
        if (parseInt(tokenDecimals) === 18) {
            unit = 1e18
            unit1 = 'ether'
        }

        amount = amount * unit;
        console.log(Math.floor(Date.now() / 1000), ' - ', 'amount', amount)

        let amountToSell = this.web3.utils.toHex(amount);
        console.log(Math.floor(Date.now() / 1000), ' - ', 'amountToSell', amountToSell)

The token decimals are just for human readability. You can just multiply the number of tokens times 10 to the power of the token decimals. So for 1.5038250054033741e+23, e+23 means times 10 to the power of 23 so it equals 150382500540337410000000 and you can use this number.

sircovsw commented 3 years ago

I am using swapExactTokensForETHSupportingFeeOnTransferTokens. Not working yet. The reason is apparently amountOutMin (https://bscscan.com/tx/0xce521e1371df7e3c4e462ef9563a6f255209e479d0bc350bd0dbaa5ffb1f130f). I'm trying to sell 0.001 BNB. I will try to figure it out. Thank you.

religion-counter commented 3 years ago

I am using swapExactTokensForETHSupportingFeeOnTransferTokens. Not working yet. The reason is apparently amountOutMin (https://bscscan.com/tx/0xce521e1371df7e3c4e462ef9563a6f255209e479d0bc350bd0dbaa5ffb1f130f). I'm trying to sell 0.001 BNB. I will try to figure it out. Thank you.

Note that UDOGE that you try to sell has very high fees - liquidity fee 10% and tax fee 1% (https://bscscan.com/address/0xd2618bc9c9cdc40ff19e200a7d14a09799c0a152#code) so you won't be able to sell your whole balance. You can try to sell first 50% and see if it works and then sell other part. I was able to sell some UDOGE with the above script but it wasn't 100% of my holdings.

sircovsw commented 3 years ago

Tell me another such moment, please. How to programmatically find out by token

Or is it not possible and all the information after the purchase of the token needs to be stored in my database?

religion-counter commented 3 years ago

Tell me another such moment, please. How to programmatically find out by token

* at what price did I buy it

* when I bought it

* what is my profit or loss now

Or is it not possible and all the information after the purchase of the token needs to be stored in my database?

It is possible but not very easy. You can check https://bscscan.com/apis#tokens for APIs that rely on the bscscan database. From there you can check for your account the transactions for the given token. From the transaction you can check the buying price. There are some limitations because the search for the transactions goes through the blockchain blocks. Also you can use the pancakeswap APIs https://github.com/pancakeswap/pancake-info-api/blob/develop/v2-documentation.md to get the current price.

sircovsw commented 3 years ago

Yes, not trivial. Thanks.

psilmana commented 2 years ago

Hi With the script i was able to perform all buy transaction but in case of sell not all transaction are executed Sell Transaction executed: approve --https://bscscan.com/tx/0x0d0a71ad59f2a034587862c9c5e4397d69e1caae5fa033ab24c9ec63564019db sell--https://bscscan.com/tx/0xc66f7a7a2ae346ecdd64d4453030ea15061992df4f0d4eeaf5a8691f0917b8ae

Sell Transaction Failed: approve -- https://bscscan.com/tx/0x7a6c23b1e976a2fa171494fe52bbf24c88db765abc093531a312b38c4b48844d Sell --- https://bscscan.com/tx/0x3b926ccc90c8af07813710838fa5ce9a6243a44f61b5eaf3db8a8f09e5992019

Both Token are 18 decimal, gas i have increased

Please tell what's the issue?

religion-counter commented 2 years ago

Hi With the script i was able to perform all buy transaction but in case of sell not all transaction are executed Sell Transaction executed: approve --https://bscscan.com/tx/0x0d0a71ad59f2a034587862c9c5e4397d69e1caae5fa033ab24c9ec63564019db sell--https://bscscan.com/tx/0xc66f7a7a2ae346ecdd64d4453030ea15061992df4f0d4eeaf5a8691f0917b8ae

Sell Transaction Failed: approve -- https://bscscan.com/tx/0x7a6c23b1e976a2fa171494fe52bbf24c88db765abc093531a312b38c4b48844d Sell --- https://bscscan.com/tx/0x3b926ccc90c8af07813710838fa5ce9a6243a44f61b5eaf3db8a8f09e5992019

Both Token are 18 decimal, gas i have increased

Please tell what's the issue?

Can you please try to sell from pancakeswap.finance and then with the script and show the two transactions. There should be some differences. Do you have enough balance? Maybe something with the token or the pair. Maybe the token supports other methods, etc.

tuncatunc commented 2 years ago

Hi,

Thank you for helper scripts!

I'm trying swap B-Token for BNB using swapExactTokensForETH on Pancakeswap Router V2

I've also tried swapExactTokensForETHSupportingFeeOnTransferTokens without and success.

It fails with TransferHelper: TRANSFER_FROM_FAILED

When I use pancakeswap.fiance and metamask it works as in this transaction https://bscscan.com/tx/0x76906d7733566ad9a020994dad44ac7cdddbf5c8d513c769488ae0d9ed96824a

However it fails when I call it from the nodejs script.

https://gist.github.com/tuncatunc/92a827da7e09f7cc9db131a326f96fc5

// Sells B for BNB from pancakeswap for address ${targetAccounts[targetIndex].address}

var fs = require('fs')
var Tx = require('ethereumjs-tx').Transaction;
var Web3 = require('web3')
var Common = require('ethereumjs-common').default;

const ankrlRpcUrl = 'https://rpc.ankr.com/bsc/';

var web3 = new Web3(new Web3.providers.HttpProvider(ankrlRpcUrl))
var BSC_FORK = Common.forCustomChain(
    'mainnet',
    {
        name: 'Binance Smart Chain Mainnet',
        networkId: 56,
        chainId: 56,
        url: ankrlRpcUrl
    },
    'istanbul',
);

var targetAccounts = [
    {
        "i": 0,
        "address": "0x9d2AC5E8A1460204D05F035ce92892fd86C489C2",
        "privateKey": "reducted"
    },
]

sellMulty();

async function sellMulty() {
    for (var i = 0; i < 1; i++) {
        var targetAccount = targetAccounts[i];
        var bAmount = 10000000; // Amount you want to sell
        const bAmountInWei = web3.utils.toWei(bAmount.toString(), 'ether')

        console.log(`${i}: Selling ${bAmount} B for BNB to pancakeswap for address ${targetAccount.address}`);
        var res = sellB(targetAccount, bAmountInWei)
            .catch(e => {
                console.error("Error in sell:", e);
                process.exit(1);
            });
        console.log(res);
        await sleep(5000 + Math.random().toFixed(4) * 10000);
    }
}

async function sellB(targetAccount, amount) {

    var amountToSell = web3.utils.toHex(amount);
    var privateKey = Buffer.from(targetAccount.privateKey.slice(2), 'hex');
    var abiArray = JSON.parse(JSON.parse(fs.readFileSync('beast-abi.json', 'utf-8')));

    var tokenAddress = '0xD96710E8419242A14D59Fe0295B0144aF66fB983'; // B contract address
    var WBNBAddress = '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c'; // WBNB token address
    var pancakeSwapRouterAddress = '0x10ed43c718714eb63d5aa57b78b54704e256024e';

    // Approve B spend
    var bContract = new web3.eth.Contract(abiArray, tokenAddress, { from: targetAccount.address });
    var approveBSpendData = bContract.methods.approve(pancakeSwapRouterAddress, web3.utils.toWei('1', 'ether'));
    var count = await web3.eth.getTransactionCount(targetAccount.address, 'pending');
    var rawTransactionApprove = {
        "from": targetAccount.address,
        "gasPrice": web3.utils.toHex(5000000000),
        "gasLimit": web3.utils.toHex(210000),
        "to": tokenAddress,
        "value": "0x0",
        "data": approveBSpendData.encodeABI(),
        "nonce": web3.utils.toHex(count)
    };
    var transactionApprove = new Tx(rawTransactionApprove, { 'common': BSC_FORK });
    transactionApprove.sign(privateKey)

    var resultApprove = await web3.eth.sendSignedTransaction('0x' + transactionApprove.serialize().toString('hex'));
    console.log("Approved" + resultApprove);

    var amountOutMin = 0; // Allow any slippage

    var routerAbi = JSON.parse(fs.readFileSync('pancake-router-abi.json', 'utf-8'));
    var contract = new web3.eth.Contract(routerAbi, pancakeSwapRouterAddress, { from: targetAccount.address });

    // var data = contract.methods.swapExactTokensForETHSupportingFeeOnTransferTokens(
    //     amountToSell,
    //     amountOutMin,
    //     [tokenAddress,
    //      '0xe9e7cea3dedca5984780bafc599bd69add087d56' /* BUSD address */, // Add this if you want to go through the onlyone-busd pair
    //      WBNBAddress],
    //     targetAccount.address,
    //     web3.utils.toHex(Math.round(Date.now()/1000)+60*20),
    // );

    var data = contract.methods.swapExactTokensForETH(
        amountToSell,
        amountOutMin,
        [tokenAddress,
            WBNBAddress],
        targetAccount.address,
        web3.utils.toHex(Math.round(Date.now() / 1000) + 60 * 20),
    );

    count = await web3.eth.getTransactionCount(targetAccount.address);
    var rawTransaction = {
        "from": targetAccount.address,
        "gasPrice": web3.utils.toHex(5000000000),
        "gasLimit": web3.utils.toHex(190830),
        "to": pancakeSwapRouterAddress,
        "value": web3.utils.toHex(0),
        "data": data.encodeABI(),
        "nonce": web3.utils.toHex(count)
    };

    var transaction = new Tx(rawTransaction, { 'common': BSC_FORK });
    transaction.sign(privateKey);

    var result = await web3.eth.sendSignedTransaction('0x' + transaction.serialize().toString('hex'));
    console.log(result)
    return result;
}

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

I'd really appreciate any help here.

religion-counter commented 2 years ago

Hi @tuncatunc, Are you sure that the input account: 0x9d2ac5e8a1460204d05f035ce92892fd86c489c2 has enough tokens to sell. Here is the difference: failed transaction:

Function: swapExactTokensForETH(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)

MethodID: 0x18cbafe5
[0]:  000000000000000000000000000000000000000000084595161401484a000000
[1]:  0000000000000000000000000000000000000000000000000000000000000000
[2]:  00000000000000000000000000000000000000000000000000000000000000a0
[3]:  0000000000000000000000009d2ac5e8a1460204d05f035ce92892fd86c489c2
[4]:  0000000000000000000000000000000000000000000000000000000062e20c92
[5]:  0000000000000000000000000000000000000000000000000000000000000002
[6]:  000000000000000000000000d96710e8419242a14d59fe0295b0144af66fb983
[7]:  000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c

successful transaction:

Function: swapExactTokensForETH(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)

MethodID: 0x18cbafe5
[0]:  000000000000000000000000000000000000000001fe861da2aaf95889340152
[1]:  0000000000000000000000000000000000000000000000000011a76a21e891c0
[2]:  00000000000000000000000000000000000000000000000000000000000000a0
[3]:  000000000000000000000000e718ee70cab22b3795fa8f70d1062336e1576e42
[4]:  0000000000000000000000000000000000000000000000000000000062e16c55
[5]:  0000000000000000000000000000000000000000000000000000000000000002
[6]:  000000000000000000000000d96710e8419242a14d59fe0295b0144af66fb983
[7]:  000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c

The only difference the input address. Can you try with the same address from pancakeswap UI?

tuncatunc commented 2 years ago

Hi @religion-counter 0x9d2ac5e8a1460204d05f035ce92892fd86c489c2 has 614,841,973.007550937535721589 BEAST

https://bscscan.com/token/0xd96710e8419242a14d59fe0295b0144af66fb983?a=0x9d2ac5e8a1460204d05f035ce92892fd86c489c2

I'm trying to sell 10000000 beasts. I convert it to Wei

var bAmount = 10000000; // Amount you want to sell const bAmountInWei = web3.utils.toWei(bAmount.toString(), 'ether')

religion-counter commented 2 years ago

Hi @religion-counter 0x9d2ac5e8a1460204d05f035ce92892fd86c489c2 has 614,841,973.007550937535721589 BEAST

https://bscscan.com/token/0xd96710e8419242a14d59fe0295b0144af66fb983?a=0x9d2ac5e8a1460204d05f035ce92892fd86c489c2

I'm trying to sell 10000000 beasts. I convert it to Wei

var bAmount = 10000000; // Amount you want to sell const bAmountInWei = web3.utils.toWei(bAmount.toString(), 'ether')

Can you try first sell half of the tokens through pancakeswap.finance and then copy the transaction with the script and execute it. The script is trying to simulate real transactions from the UI. There is some difference in your use case. Is the token approved?

tuncatunc commented 2 years ago

I tried 314841973 Beast token -> BNB swap. Only [1] is different. It is the amountOutMin parameter. I did set it to 0 to allow any slippage amount. That was my fault.

Then I set the amountOutMin to value from the pancakeswap UI. The transaction is now success.

Here is successful transaction https://bscscan.com/tx/0xac9bf96ace05b8e23d5c3406c835c72ab433c265d09da8b94a4e0ddb46e8b224

Thank you a lot for pointing out the Input Data differences.

🎉


EDIT: The problem is now how to calculate amountOutMin, the amountOut * 0.95 from getAmountsOut still causes the swap fail.

religion-counter commented 2 years ago

It is strange, before with other tokens with 0 amountOutMin it worked. But maybe something in the newer versions of pancakeswap. You can check https://docs.uniswap.org/sdk/2.0.0/guides/pricing for price apis, also you can get the amount of token and bnb for example in the pair contract and divide the token to bnb to get the current price. Glad to hear that now it works but about the price, yes.. Have you tried with other token?

tuncatunc commented 2 years ago

It only works if I get the amountOutMin parameter from pancakeswap ui. I’ll be digging more. The pricing api getAmountsOut doesn’t give me the correct values too. I’ll be digging more

religion-counter commented 2 years ago

Good luck. Please post if you find a solution. Thanks!

tuncatunc commented 2 years ago

The problem was here

    var approveBSpendData = bContract.methods.approve(pancakeSwapRouterAddress, web3.utils.toWei('1', 'ether'));

I only approved pancakeswap to spend 1 B Token, I increased the approved amount and voila!