Categories
discuss

I am trying to execute a swap on Pancakeswap using web3, but I get an error when calculating transaction cost

I am new at ethereum development and I am working on a simple script to execute swaps using Pancakeswap. Everything seems to be working well up to the point where I am building my transaction and calculate the tx-cost. I am using the UniswapRouterV02 abi create my Pancakeswap contract. The code:

const init = async () => {

    const [WBNB, BUSD] = await Promise.all(
        [addresses.WBNB, addresses.BUSD].map(tokenAddress => (
            new Token(
                ChainId.MAINNET,
                tokenAddress,
                18
            )
        )));


    const pair = await Fetcher.fetchPairData(WBNB, BUSD, provider)
    const route = await new Route([pair], WBNB)
    const trade = await new Trade(route, new TokenAmount(WBNB, tradeAmount), TradeType.EXACT_INPUT)
    const executionPrice = trade.executionPrice.toSignificant(12)

    // Correct prices; everything seems correct up until here

    const slippageTolerance = new Percent('50', '10000')

    const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw
    const path = [WBNB.address, BUSD.address]
    const to = MY_ADDRESS
    const deadline = Math.floor(Date.now() / 1000) + 60 * 20
    const value = trade.inputAmount.raw

    // Correct prices everything seems correct up until here

    const pancakeSwap = new web3.eth.Contract(
        abis.uniswapRouter.abi,
        addresses.PANCAKE_ROUTER //'0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F'
    );

    let tx = pancakeSwap.methods.swapExactTokensForTokens(
        tradeAmount,
        web3.utils.toBN(amountOutMin.toString()),
        path,
        to,
        deadline
    )

    const [gasPrice, gasCost] = await Promise.all([
        web3.eth.getGasPrice(),
        tx.estimateGas({from: admin}),
    ]);


    console.log(`gasPrice: ${gasPrice}`)
    console.log(`gasCost: ${gasCost}`)
}

init()

The price calculation for the swap returns correct prices. However when I try to calculate the transaction costs the following error is thrown: Error: Returned error: gas required exceeds allowance (44038122) or always failing transaction

Any help would be greatly appreciated, please let me know if more of my code should be clarified!

Answer

In turns out that with web3 it is not possible to interact with the Pancakeswap contract. I found a solution using ethers.js. Following code worked for me to execute a swap on Pancake on mainnet. Before executing the first transaction Pancakeswap needs to be allowed, this code is commented out. I had to play around with the gasprice and gasLimit a bit to make it work.

require("dotenv").config()
const ethers = require('ethers')
const {ChainId, Token, TokenAmount, Fetcher, Pair, Route, Trade, TradeType, Percent} = 
require('@pancakeswap-libs/sdk');
const Web3 = require('web3');
const web3 = new Web3('wss://apis.ankr.com/wss/c40792ffe3514537be9fb4109b32d257/946dd909d324e5a6caa2b72ba75c5799/binance/full/main');
const {JsonRpcProvider} = require("@ethersproject/providers");
const provider = new JsonRpcProvider('https://bsc-dataseed1.binance.org/');
const { address: admin } = web3.eth.accounts.wallet.add(process.env.PRIVATE_KEY)

const addresses = {
    WBNB: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c',
    BUSD: '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56',
    PANCAKE_ROUTER: '0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F'
}

const ONE_ETH_IN_WEI = web3.utils.toBN(web3.utils.toWei('1'))
const tradeAmount = ONE_ETH_IN_WEI.div(web3.utils.toBN('1000'))

const init = async () => {

const [WBNB, BUSD] = await Promise.all(
    [addresses.WBNB, addresses.BUSD].map(tokenAddress => (
        new Token(
            ChainId.MAINNET,
            tokenAddress,
            18
        )
    )));

const pair = await Fetcher.fetchPairData(WBNB, BUSD, provider)
const route = await new Route([pair], WBNB)
const trade = await new Trade(route, new TokenAmount(WBNB, tradeAmount), TradeType.EXACT_INPUT)

const slippageTolerance = new Percent('50', '10000')

// create transaction parameters
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw
const path = [WBNB.address, BUSD.address]
const to = admin
const deadline = Math.floor(Date.now() / 1000) + 60 * 20

// Create signer
const wallet = new ethers.Wallet(
    Buffer.from(
    process.env.PRIVATE_KEY, // paste your private key from metamask here
    "hex"
    )
)
const signer = wallet.connect(provider)

// Create Pancakeswap ethers Contract
const pancakeswap = new ethers.Contract(
    addresses.PANCAKE_ROUTER,
    ['function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)'],
    signer
)

// Allow Pancakeswap
// let abi = ["function approve(address _spender, uint256 _value) public returns (bool success)"]
// let contract = new ethers.Contract(WBNB.address, abi, signer)
// await contract.approve(addresses.PANCAKE_ROUTER, ethers.utils.parseUnits('1000.0', 18), {gasLimit: 100000, gasPrice: 5e9})

// Execute transaction
const tx = await pancakeswap.swapExactTokensForTokens(
    ethers.utils.parseUnits('0.001', 18),
    ethers.utils.parseUnits(web3.utils.fromWei(amountOutMin.toString()), 18),
    path,
    to,
    deadline,
    { gasLimit: ethers.utils.hexlify(200000), gasPrice: ethers.utils.parseUnits("10", "gwei") }
)

console.log(`Tx-hash: ${tx.hash}`)

const receipt = await tx.wait();

console.log(`Tx was mined in block: ${receipt.blockNumber}`)
}

init()
Categories
discuss

Android isShrinkResources removed by gradle plugin 7.0.0-alpha15. How to shrink resources?

Latest Android gradle plugin 7.0.0-alpha15 removed the option isShrinkResources in BuildType.
Does isMinifyEnabled now superseeds it, or is there a new way to ensure the resources will be shrinked when building the app?

Answer

According to Google, the missing isShrinkResources issue is fixed in an upcoming AGP 7.0-beta1
https://issuetracker.google.com/issues/186806256

Categories
discuss

Is openJdk upgrading to 8u292 break my aosp build system?

Software environment:

  • Ubuntu 20.04 LTS server;
  • Android AOSP 8.0;
  • OpenJDK 8;

It works very well util yesterday I upgraded my OpenJDK from 8u282 to 8u292. Now the broken building log says:

Ensuring Jack server is installed and started
FAILED: setup-jack-server
/bin/bash -c "(prebuilts/sdk/tools/jack-admin install-server prebuilts/sdk/tools/jack-launcher.jar prebuilts/sdk/tools/jack-server-4.11.ALPHA.jar  2>&1 || (exit 0) ) && (JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation" prebuilts/sdk/tools/jack-admin start-server 2>&1 ||
 exit 0 ) && (prebuilts/sdk/tools/jack-admin update server prebuilts/sdk/tools/jack-server-4.11.ALPHA.jar 4.11.ALPHA 2>&1 || exit 0 ) && (prebuilts/sdk/tools/jack-admin update jack prebuilts/sdk/tools/jacks/jack-4.32.CANDIDATE.jar 4.32.CANDIDATE || exit 47 )"
Jack server already installed in "~/.jack-server"
Launching Jack server java -XX:MaxJavaStackTraceDepth=-1 -Djava.io.tmpdir=/tmp -Dfile.encoding=UTF-8 -XX:+TieredCompilation -cp ~/.jack-server/launcher.jar com.android.jack.launcher.ServerLauncher
Jack server failed to (re)start, try 'jack-diagnose' or see Jack server log
SSL error when connecting to the Jack server. Try 'jack-diagnose'
SSL error when connecting to the Jack server. Try 'jack-diagnose'
ninja: build stopped: subcommand failed.
10:11:50 ninja failed with: exit status 1

I checked the log in ~/.jack-server/log/xxxx-0-0.log. It has nothing about error.

I use curl command to connect to the server, it says:

$ curl https://127.0.0.1:8076/jack
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:8076

I changed the script in prebuilts/sdk/tools/jack-admin to print the $CURL_CODE, samed as my shell curl command, report error code 35.

This url discussed about samliar problem: https://forums.gentoo.org/viewtopic-t-1060536-start-0.html

But I am not sure.

Here is the source script link which prompts the above error: https://android-opengrok.bangnimang.net/android-8.1.0_r81/xref/prebuilts/sdk/tools/jack-admin?r=692a2a62#89

Answer

I have same issue and it was fixed by removing “TLSv1, TLSv1.1” in jdk.tls.disabledAlgorithms configuration in file /etc/java-8-openjdk/security/java.security.

Categories
discuss

Why is the data array in java.util.ArrayList package-private?

In the java.util.ArrayList class, the object array for the list’s elements is defined as package-private:

transient Object[] elementData; // non-private to simplify nested class access

The comment states that the reason why this field is not private is easier access in nested classes. However, nested classes can access private data of the enclosing class just fine. So why is elementData not private? Is there something happening in the background (e.g., at compilation time)?

Answer

When you access a private field from a nested class, the compiler actually generates a synthetic accessor method that is package-visible, and then uses that for the access. It can’t access the private member directly, so to avoid that indirection you can make the member package-visible instead.

Here’s an answer with more details.

Categories
discuss

group by array of objects with condition and custom key

I have below array of objects,

[{

    a: 1,
    created_on: '2021-04-23 10:00:01',
}, {
    b: 1,
    created_on: '2021-04-24 09:03:01',
}, {
    b: 1,
    created_on: '2021-04-24 13:03:01',
}]

First, I need to group by with date ignoring times.

So,

{
 "2021-04-23": [{
    a: 1,
    created_on: '2021-04-23 10:00:01',
  }],
....
}

If it were a date like created_on: '2021-04-23', I could use lodash/groupBy.

I still could use it but now it involves some condition to be applied to convert those created_on into date format.

Further, I also need to group by those each grouped by date result as such that their created_on falls within a time interval.

"SALES_SLOTS": [
    {
      "slot": "00:00-04:00"
    },
    {
      "slot": "04:00-08:00"
    }, 
    {
      "slot":"08:00-12:00"
    }, 
    {
      "slot":"12:00-16:00"
    },
    {
      "slot":"16:00-20:00"
    },
    {
      "slot":"20:00-24:00"
    }
  ],

So, if created_on: '2021-04-23 10:00:01', it should come in the group,

{
  "08:00-12:00": [{
     a: 1,
     created_on: '2021-04-23 10:00:01',
  }]
}

So, first results should be grouped by date from created on and then elements in each groups should be further group by defined time slots.

I suppose, if I could use group by condition, I could achieve the desired result.

Answer

Vanilla JS


Using Array#reduce with Map.

  1. Grouping by date is fairly simple, you can group the data by created_on.slice(0, 10) using a Map.

  2. Then I’ve created a helper function getSlot that returns a slot based on the time passed. Now, since your slots are fairly wide, testing just the hour part would be sufficient.

  3. Next, for every group of date, again group it by time using getSlot helper and Map and using Object.fromEntries you can get the desired object.

NOTE: I’ve used expressions instead of statements inside my code (using commas, defaulted parameters) which is just a preferential choice.

const 
  arr = [{ a: 1, created_on: "2021-04-23 10:00:01" }, { b: 1, created_on: "2021-04-24 09:03:01" }, { b: 1, created_on: "2021-04-24 13:03:01" }],
  
  slots = [{ slot: "00:00-04:00" }, { slot: "04:00-08:00" }, { slot: "08:00-12:00" }, { slot: "12:00-16:00" }, { slot: "16:00-20:00" }, { slot: "20:00-24:00" }],
      
  grpDate = Array.from(
    arr.reduce(
      (m, o, _i, _arr, d = o.created_on.slice(0, 10)) => (
        m.has(d) ? m.get(d).push(o) : m.set(d, [o]), m
      ),
      new Map()
    )
  ),
  
  getSlot = (time) =>
    slots
      .find(({ slot }) => time >= slot.slice(0, 2) && time < slot.slice(6, 8))
      .slot,
      
  grpSlot = grpDate.map(([k, v]) =>
    [k, Object.fromEntries(v.reduce(
      (m, o, _i, _arr, slot = getSlot(o.created_on.slice(11, 13))) => (
        m.has(slot) ? m.get(slot).push(o) : m.set(slot, [o]), m
      ),
      new Map()
    ))]
  );

console.log(Object.fromEntries(grpSlot));

Screenshot of the output


enter image description here

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..