execution reverted: uniswapv2library: insufficient_input_amount when using swapExactTokensForETHSupportingFeeOnTransferTokens - ethereum

I am facing the error, execution reverted: uniswapv2library: insufficient_input_amount when using swapExactTokensForETHSupportingFeeOnTransferTokens.
The tokenAmount is 18 decimals. (8072364872364293879238745)
There is enough liquidity in the pool and i have swapped this exact amount using the uniswap app with no problems, multiple times.
function swapTokensForEth(uint256 tokenAmount) private {
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapV2Router.WETH();
_approve(address(this), address(uniswapV2Router), tokenAmount);
uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0,
path,
address(this),
block.timestamp
);
}
Please Help!

Your code looks fine, so i assume you have another problem that the tokenAmount you are passing to the contract is zero.
The only time this error occurs is when the input is zero.
https://github.com/Uniswap/v2-periphery/blob/dda62473e2da448bc9cb8f4514dadda4aeede5f4/contracts/libraries/UniswapV2Library.sol

Related

Gas efficiency of totalSupply() vs. a tokenID counter | ERC-721

I'm creating a solidity contract for an NFT and in my mint function I'm not sure if a call to totalSupply() vs using a token counter and incrementing it is better practice. Does either variation cost more gas? Is one the more standard practice? I've seen examples of both being used.
Variation 1:
contract MyNFT is ERC721Enumerable, PaymentSplitter, Ownable {
using Counters for Counters.Counter;
Counters.Counter private currentTokenId;
...
function mint(uint256 _count)
public payable
{
uint256 tokenId = currentTokenId.current();
require(tokenId < MAX_SUPPLY, "Max supply reached");
for(uint i = 0; i < _count; ++i){
currentTokenId.increment();
uint256 newItemId = currentTokenId.current();
_safeMint(msg.sender, newItemId);
}
}
}
Variation 2:
function mint(uint256 _count)
public payable
{
uint supply = totalSupply();
require( supply + _count <= MAX_SUPPLY, "Exceeds max supply." );
for(uint i = 0; i < _count; ++i){
_safeMint(msg.sender, supply + i);
}
}
Both versions seem to work. I just want to be sure I'm using the most efficient / secure. Thanks for any advice!
First off all, you need to show us the underlying implementations. However, I can speculate that these are unmodified openzeppelin implementations for ERC721Enumerable and Counters.
For your case only, using Counter seems a little bit pointless to me.
It increases your deployment costs(just a little bit) because of redundant code coming from Counter library
You already know the length of your tokens array, why keep it twice? Counters is created for situations where you don't know the number of elements, like a mapping.
I am not guaranteeing correctness of the following analysis
Calling totalSupply (looking from opcode point of view) will:
jump to totalsupply (8 gas)
sload tokens.slot (200) gas
However, while using Counter, you sstore (>= 5000 gas) each time you decrement and sload (200 gas) each time you read.
As long as i am not mistaken about Counter using storage, and therefore sstore and sload opcodes, second variant will use much less gas.

Need help understanding solidity contract function swapback()

I have recently been delving into the code of a few contracts and have been commenting them myself to try and understand how they work as the entire field seems ironically black-box from a development perspective with most code copy and pasted from other contracts with 0 comments explaining what functions do.
As such I have seen a recurring function across multiple projects which I am struggling to get my head around. Namely shouldswapback() and swapback().
shouldSwapBack():
function shouldSwapBack() internal view returns (bool) {
return msg.sender != pair
&& !inSwap
&& swapEnabled
&& _balances[address(this)] >= swapThreshold;
}
My understanding of above is to return true only when the caller of the function is not the LP address, swapping is allowed and we are not in a swap currently and the balance of the contract is >= the predefined swap threshold.
2 questions regarding this:
1. In what context/circumstance is the msg.sender the LP contract?
2. Why is it important to only swap if the contract balance is greater than a certain percentage? What would be the effect if this was 0?
The actual swap function is longer:
function swapBack() internal swapping {
uint256 contractTokenBalance = balanceOf(address(this));
/* (contract balance * 3)/15/2 */
uint256 amountToLiquify = contractTokenBalance.mul(liquidityFee).div(totalFee).div(2);
uint256 amountToSwap = contractTokenBalance.sub(amountToLiquify);
/* set the address path for the BNB and Token addresses */
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = WBNB;
/* note before balance of contract */
uint256 balanceBefore = address(this).balance;
/*swap tokens using PCS */
router.swapExactTokensForETHSupportingFeeOnTransferTokens(
amountToSwap, /*The amount of input tokens to send. */
0, /*The minimum amount of output tokens that must be received for the transaction not to revert. */
path, /*An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity. */
address(this), /*Recipient of the BNB. */
block.timestamp /*Unix timestamp after which the transaction will revert. (Think set to one block?)*/
);
uint256 amountBNB = address(this).balance.sub(balanceBefore); /* get amount swapped by checking new contract balance vs beforeswap */
uint256 totalBNBFee = totalFee.sub(liquidityFee.div(2));
uint256 amountBNBLiquidity = amountBNB.mul(liquidityFee).div(totalBNBFee).div(2);
uint256 amountBNBMarketing = amountBNB.mul(marketingFee).div(totalBNBFee);
/* send marketing fee to marketing wallet */
(bool MarketingSuccess, /* bytes memory data */) = payable(marketingFeeReceiver).call{value: amountBNBMarketing, gas: 30000}("");
require(MarketingSuccess, "receiver rejected ETH transfer");
/* if we meet the liquidity threshold add to marketwallet */
if(amountToLiquify > 0){
router.addLiquidityETH{value: amountBNBLiquidity}(
address(this),
amountToLiquify,
0,
0,
marketingFeeReceiver,
block.timestamp
);
emit AutoLiquify(amountBNBLiquidity, amountToLiquify);
}
}
My understanding for this is that the contract tokens are swapped to BNB and then the fees are calculated and sent to the appropriate wallet. However with this I don't understand:
1.Why are the tokens going the contract and not the LP?
2.If all the tokens are swapped to ETH do none get swapped back?
3.What is the significance of adding to the LP, why would this be necessary? (if this wasn't done what would the affect be on the token? I have seen projects fail in the past because they didn't buyback liquidity but I'm struggling to understand what it would do apart from ease volatility?)
I understand that this a lengthy question and my issue seems to be less from a code perspective and more from a key concept one but if anyone could help me it would be great. I have looked online for courses but none seem to really delve into dex interactions, a lot just seem very basic token/NFT creation I haven't been able to find one tutorial on making a contract that has a working tax implementation so instead I've just been cross referencing a bunch of different contracts.
If anyone can point me in the right direction for a course or even better a tutor that would be great.
Thanks.

Implementing Uniswap v3 API single swap example on scaffold-eth - ERROR: cannot estimate gas

Using scaffold-eth to implement this single swap example from the uniswap documentation.
Pretty much just copied and pasted the code and was able to deploy it successfully to rinkeby:
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
pragma abicoder v2;
import "hardhat/console.sol";
import '#uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
import '#uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
contract YourContract {
// For the scope of these swap examples,
// we will detail the design considerations when using
// `exactInput`, `exactInputSingle`, `exactOutput`, and `exactOutputSingle`.
// It should be noted that for the sake of these examples, we purposefully pass in the swap router instead of inherit the swap router for simplicity.
// More advanced example contracts will detail how to inherit the swap router safely.
ISwapRouter public immutable swapRouter;
// This example swaps DAI/WETH9 for single path swaps and DAI/USDC/WETH9 for multi path swaps.
address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
// For this example, we will set the pool fee to 0.3%.
uint24 public constant poolFee = 3000;
constructor(ISwapRouter _swapRouter) {
swapRouter = _swapRouter;
}
/// #notice swapExactInputSingle swaps a fixed amount of DAI for a maximum possible amount of WETH9
/// using the DAI/WETH9 0.3% pool by calling `exactInputSingle` in the swap router.
/// #dev The calling address must approve this contract to spend at least `amountIn` worth of its DAI for this function to succeed.
/// #param amountIn The exact amount of DAI that will be swapped for WETH9.
/// #return amountOut The amount of WETH9 received.
function swapExactInputSingle(uint256 amountIn) external returns (uint256 amountOut) {
// msg.sender must approve this contract
// Transfer the specified amount of DAI to this contract.
TransferHelper.safeTransferFrom(DAI, msg.sender, address(this), amountIn);
// Approve the router to spend DAI.
TransferHelper.safeApprove(DAI, address(swapRouter), amountIn);
// Naively set amountOutMinimum to 0. In production, use an oracle or other data source to choose a safer value for amountOutMinimum.
// We also set the sqrtPriceLimitx96 to be 0 to ensure we swap our exact input amount.
ISwapRouter.ExactInputSingleParams memory params =
ISwapRouter.ExactInputSingleParams({
tokenIn: DAI,
tokenOut: WETH9,
fee: poolFee,
recipient: msg.sender,
deadline: block.timestamp,
amountIn: amountIn,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
// The call to `exactInputSingle` executes the swap.
amountOut = swapRouter.exactInputSingle(params);
}
/// #notice swapExactOutputSingle swaps a minimum possible amount of DAI for a fixed amount of WETH.
/// #dev The calling address must approve this contract to spend its DAI for this function to succeed. As the amount of input DAI is variable,
/// the calling address will need to approve for a slightly higher amount, anticipating some variance.
/// #param amountOut The exact amount of WETH9 to receive from the swap.
/// #param amountInMaximum The amount of DAI we are willing to spend to receive the specified amount of WETH9.
/// #return amountIn The amount of DAI actually spent in the swap.
function swapExactOutputSingle(uint256 amountOut, uint256 amountInMaximum) external returns (uint256 amountIn) {
// Transfer the specified amount of DAI to this contract.
TransferHelper.safeTransferFrom(DAI, msg.sender, address(this), amountInMaximum);
// Approve the router to spend the specifed `amountInMaximum` of DAI.
// In production, you should choose the maximum amount to spend based on oracles or other data sources to achieve a better swap.
TransferHelper.safeApprove(DAI, address(swapRouter), amountInMaximum);
ISwapRouter.ExactOutputSingleParams memory params =
ISwapRouter.ExactOutputSingleParams({
tokenIn: DAI,
tokenOut: WETH9,
fee: poolFee,
recipient: msg.sender,
deadline: block.timestamp,
amountOut: amountOut,
amountInMaximum: amountInMaximum,
sqrtPriceLimitX96: 0
});
// Executes the swap returning the amountIn needed to spend to receive the desired amountOut.
amountIn = swapRouter.exactOutputSingle(params);
// For exact output swaps, the amountInMaximum may not have all been spent.
// If the actual amount spent (amountIn) is less than the specified maximum amount, we must refund the msg.sender and approve the swapRouter to spend 0.
if (amountIn < amountInMaximum) {
TransferHelper.safeApprove(DAI, address(swapRouter), 0);
TransferHelper.safeTransfer(DAI, msg.sender, amountInMaximum - amountIn);
}
}
}
Also learned to edit my deployer to add in the args for the constructor, and made sure to pass the SwapRouter address from here:
await deploy("YourContract", {
// Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
from: deployer,
args: [ '0xE592427A0AEce92De3Edee1F18E0157C05861564' ],
log: true,
waitConfirmations: 5,
});
This all worked, and I am able to see this in the debug console on my local scaffold-eth, running on rinkeby:
I also made sure to have enough funds in my wallet for gas, etc:
When I try to hit send in the swapExactInputSingle function for any amount of DAI, I get the following error every time:
{
"reason":"cannot estimate gas; transaction may fail or may require manual gas limit",
"code":"UNPREDICTABLE_GAS_LIMIT",
"error":{
"code":-32000,
"message":"execution reverted"
},
"method":"estimateGas",
"transaction":{
"from":"0xF59FBfd44C9e495542D46109F81416bd3fC38Ed7",
"to":"0xcFc57b48365133105F6877a02126673B7b906a55",
"data":"0x73bd43ad000000000000000000000000000000000000000000000000000000000000000a",
"accessList":null
}
}
I get this error as soon as I hit send, and am never prompted to approve my DAI or anything else. Other simple contracts have worked and I am able to send transactions on Rinkeby properly, so assume this is due to the added complexity of using the Uniswap API, etc.
The recipient is not msg.sender, it should be address(this). Also you have to take care of the functions TransferHelper, who is going to receive, who is going to send.
try setting your config to look like this. I believe the issue you are experiencing is caused by metamask improperly estimating gas
networks: {
hardhat: {
forking: {
url: `https://eth-mainnet.alchemyapi.io/v2/YOUR_KEY_HERE`,
// url: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`,
// url: 'http://localhost:8545',
},
gasPrice: 0,
initialBaseFeePerGas: 0,
}
The token address of DAI, WETH9, USDC are of the Ethereum mainnet and you have deployed it on Rinkeby. You have to use the token contract address of Rinkeby.
Not sure about any other issues if present.

sellPrice and buyPrice Solidity

I have a problem trying to put my sellPrice to 0.01 and my buyPrice equals to 0.02.
My contract is deployed and later I use setPrices function to set token price. I put with doble quotes "10000000000000000" and "20000000000000000" because if I put without that throw an exception.
Buy function:
/// #notice Buy tokens from contract by sending ether
function buy() payable public {
uint amount = msg.value / buyPrice; // calculates the amount
_transfer(this, msg.sender, amount); // makes the transfers
}
On my web3 code:
$('#buy').click(function(){
Compra.buy({
gas: 300000,
from: web3.eth.coinbase,
value: 20000000000000000
},function(error,res){
console.log(res);
if(!error){
if(res.blockHash != $("#insTrans").html())
$("#loader").hide();
$("#insTrans").html("Block hash: " + res.blockHash)
}else{
$("#loader").hide();
console.log(error);
}
});
});
When buy() is success add to my wallet 0.000000000000000001 of my tokens and I want 1 token on my wallet. I mean 0.02 = 1 mytokens.
Someone can help me please? I am very stuck here.
Thanks.
It is due to the fact you are using decimals. If you use the standardized 18 decimal format, you need to multiply the buy price by 180 (or 10**decimals) as mentioned in the comments above.
As #smarx said above, you can change the code to
msg.value / buyPrice * 10**decimals

Sometimes I lose array items in Ethereum smart-contract

I have found strange problem in my smart contract. I use testrpc (v4.1.3) and last MetaMask as local dev environment.
Please, see code below (it is short version, just place with problem):
struct PayRecord {
address sender;
uint256 sum;
uint256 blockNumber;
uint256 status;
}
event PaymentPlaced(address senderAddress, uint256 blockNumber, uint256 payIndex, string guid);
PayRecord[] public payments;
function payForSomething(string guid) payable {
uint256 newLength = payments.push(PayRecord(msg.sender, msg.value, block.number, 0));
PaymentPlaced(msg.sender, block.number, newLength-1, guid);
}
function changeSomething(uint256 paymentIndex) {
if(payments[paymentIndex].status == 0){
payments[paymentIndex].status == 1;
}
}
Often everything works fine:
user calls function payForSomething()
user gets event PaymentPlaced in browser
user calls changeSomething()
but...
SOMETIMES I have next problem:
user calls payForSomething()
user gets event PaymentPlaced (for example: blockNumber = 10, payIndex = 5).
user calls changeSomething() - and gets error "invalid opcode"
if user calls payForSomething() again - he gets event PaymentPlaced with data (blockNumber == 15, payIndex = 5)
The same array length, different block numbers, two insertion events...
So...Sometimes it happens, sometimes everything works fine. I always have only one user, only I works with this smart-contract (I'm still developing it).
Why do I lose items from array?