implementing UniswapV2 swapExactTokensForETH failed - smartcontracts

following the Smart Contract Integration / Implement a Swap, my contact likes below
contract UniDemo {
function swapTokensForETH(uint amountIn, uint amountOutMin, uint deadline) public payable returns(uint) {
// transfer
require(Token.transferFrom(msg.sender, address(this), amountIn), 'transferFrom failed.');
// approve
require(Token.approve(UNISWAP_ROUTER_ADDRESS, amountIn), 'approve failed.');
// swap
uint[] memory outs = uniswapRouter.swapExactTokensForETH(amountIn, amountOutMin, getPathForTokenToETH(), msg.sender, deadline);
return outs[1];
}
}
I keep getting EVM revert error, Is this something wrong?
Example tx: 0x080555abe5287a8e7d67a9129e9464d2773955371fd9ffcf6e81b301d0a7f4df

Looks like you are not receiving any response from the router (uniswapRouter), so return outs[1] throws a revert error as your outs array is empty.

Related

What to do to solve unpredictable gas fees from a function in a smart contract using boolean?

The smart contract I have written seems to have an error where the gas fees are unpredictable and even if I increase the max limit, the transaction fails and gets reverted. This specific function uses a bool and am wondering if it is the cause.
I was trying to pass the function goodsDelivered with the exchangeID which is the transaction hash from executing function openExchange, however when I try changing the goodsDelivered to 'true', I get a warning from metamask stating: unpredictable_gas_limit and gets reverted. Initially I thought it was an error from the client side where I wrote js code to be able to interact with the smart contract but when I tried writing on etherscan directly there was also the transaction failed. I have also tried debugging on Remix but it functions fine on remix.
pragma solidity ^0.8.0;
contract Exchange{
struct exchange{
uint amount;
address buyer;
address seller;
address agent;
bool goodsDelivered;
}
constructor() {
}
uint nonce;
mapping (bytes32 => exchange) public exchangeRegistry;
function openExchange(address _seller, address _agent) external payable returns (bytes32 _exchangeId) {
address _buyer = msg.sender;
uint _amount = msg.value;
_exchangeId = keccak256(abi.encodePacked(_buyer, nonce));
exchangeRegistry[_exchangeId].amount = _amount;
exchangeRegistry[_exchangeId].buyer = _buyer;
exchangeRegistry[_exchangeId].seller = _seller;
exchangeRegistry[_exchangeId].agent = _agent;
nonce += 1;
}
function withdrawAmount(bytes32 _exchangeId) external payable returns (bool){
require((exchangeRegistry[_exchangeId].goodsDelivered == true && msg.sender == exchangeRegistry[_exchangeId].seller)
|| (exchangeRegistry[_exchangeId].goodsDelivered == false && msg.sender == exchangeRegistry[_exchangeId].buyer));
payable(msg.sender).transfer(exchangeRegistry[_exchangeId].amount);
return (true);
}
function goodsDelivered(bytes32 _exchangeId, bool _goodsDelivered) external returns (bool){
require(msg.sender == exchangeRegistry[_exchangeId].agent);
exchangeRegistry[_exchangeId].goodsDelivered = _goodsDelivered;
}
}

Adding Liquidity to Pancakeswap in Testnet

I need help with my code. I want to create a simple Smart Contract with adding Liquidity to Pancakeswap. I tried many different things, but the transaction always fails.
I Deployed the Conract,
added BNB to this Contract
and then i want to call the addInitialLiquidity function to set the Liquiditypool.
This is my Errorcode:
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "code": 3, "message": "execution reverted: TransferHelper: TRANSFER_FROM_FAILED", "data": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000245472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c454400000000000000000000000000000000000000000000000000000000" }
And this is the Smart Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeMath.sol";
import "https://github.com/Uniswap/v2-periphery/blob/master/contracts/interfaces/IUniswapV2Router02.sol";
import "https://github.com/Uniswap/v2-core/blob/master/contracts/interfaces/IUniswapV2Factory.sol";
contract CWCoin is ERC20, Ownable{
using SafeMath for uint256;
uint8 liquiFee = 1;
IUniswapV2Router02 public uniswapV2Router;
address public uniswapV2Pair;
bool initialLiqDone = false;
constructor ()
ERC20("CWCoin", "CWC"){
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(
0xD99D1c33F9fC3444f8101754aBC46c52416550D1
);
address _uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
uniswapV2Router = _uniswapV2Router;
uniswapV2Pair = _uniswapV2Pair;
_mint(msg.sender, 1000000 * 10 ** uint(decimals()) );
_mint(address(this), 100000 * 10 ** uint(decimals()) );
}
receive() external payable{}
function swapAndLiquify(uint256 tokens) private {
// split the contract balance into halves
uint256 half = tokens.div(2);
uint256 otherHalf = tokens.sub(half);
uint256 initialBalance = address(this).balance;
// swap tokens for ETH
swapTokensForEth(half); // <- this breaks the ETH -> HATE swap when swap+liquify is triggered
// how much ETH did we just swap into?
uint256 newBalance = address(this).balance.sub(initialBalance);
// add liquidity to uniswap
addLiquidity(otherHalf, newBalance);
}
function addInitialLiquidity() public onlyOwner{
// approve token transfer to cover all possible scenarios
_approve(address(this), address(uniswapV2Router), ~uint256(0));
_approve(address(this), address(uniswapV2Pair), ~uint256(0));
// add the liquidity
uniswapV2Router.addLiquidityETH{value: address(this).balance}(
address(this),
balanceOf(address(this)),
0, // slippage is unavoidable
0, // slippage is unavoidable
owner(),
block.timestamp
);
initialLiqDone = true;
}
function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
// approve token transfer to cover all possible scenarios
_approve(address(this), address(uniswapV2Router), tokenAmount);
// add the liquidity
uniswapV2Router.addLiquidityETH{value: ethAmount}(
address(this),
tokenAmount,
0, // slippage is unavoidable
0, // slippage is unavoidable
address(0),
block.timestamp
);
}
function swapTokensForEth(uint256 tokenAmount) private {
// generate the uniswap pair path of token -> weth
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapV2Router.WETH();
_approve(address(this), address(uniswapV2Router), tokenAmount);
// make the swap
uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0, // accept any amount of ETH
path,
address(this),
block.timestamp
);
}
function _transfer(
address from,
address to,
uint256 amount
) internal override{
require(from != address(0), "From not null address");
require(to != address(0), "To not null address");
if(amount == 0){
super._transfer(from, to, 0);
return;
}
uint256 liqui = amount.mul(liquiFee).div(100);
swapAndLiquify(liqui);
super._transfer(from, to, amount.sub(liqui));
}
}
Smart Contract in Testnet
0xF0e54bA09c3e7E66f414dCE375f5FAE6846041F7
Transaction
0xa80e9acbf7310de437f41afdf19f9554bdd846c37ad004dc8efbec9c29093cb2
I hope anyone can help.
Thank you very much
Edit:
I tried many different things.
Approved the Router,
Approved the Pair,
Approved my wallet Address
I tried to add Liquidity via bscscan. Nothing worked.
The exception is originating from IUniswapV2Router02 contract, in safeTransferFrom function of TransferHelper library. This function wants to transfer your tokens to pair contract by calling transferFrom function of your contract. Pancakeswap will assume the transfer succeeded if you return true in the transferFrom function. I checked your contract on bscscan testnet but it's not verified and so I couldn't read what transferFrom function is doing. I'm guessing it's calling _transfer but then not returning true when it's done.

Sending ERC20 tokens using the transfer function

I'm pretty new to programing in solidity and I'm currently trying to run a simple smart contract in Remix, seen bellow:
pragma solidity ^0.8.0;
import "github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
contract Swap {
address public owner;
uint256 public balance;
event TransferReceived(address _from, uint _amount);
event TransferSent(address _from, address _destAddr, uint _amount);
constructor() {
owner = msg.sender;
}
receive() payable external {
balance += msg.value;
emit TransferReceived(msg.sender, msg.value);
}
function withdraw(uint amount, address payable destAddr) public {
require(msg.sender == owner, "Only owner can withdraw funds");
require(amount <= balance, "Insufficient funds");
destAddr.transfer(amount);
balance -= amount;
emit TransferSent(msg.sender, destAddr, amount);
}
function transferERC20(IERC20 token, address to, uint256 amount) public {
require(msg.sender == owner, "Only owner can withdraw funds");
uint256 erc20balance = token.balanceOf(address(this));
require(amount <= erc20balance, "balance is low");
token.transfer(to, amount);
emit TransferSent(msg.sender, to, amount);
}
}
While I can successfully send BNB and call the withdraw function giving the value sent and my wallet address in the BSC testnet, I'm having issues when running the transferERC20 function. The only output that I get when calling this method is the following message:
Gas estimation errored with the following message (see below). The
transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "code": -32000, "message": "execution
reverted" }
I've tried several different addresses that I found in the testnet.bscscan website for BNB while making sure that the contract had enough funds for transfering, but I had no success.
Can someone suggest what might be going wrong in my contract/setup? Am I making this transfer properly?
fix constrcutor
constructor() {
// payable allows payment of ether with a call.
owner = payable(msg.sender);
}
make sure those require statements are satisfied
require(msg.sender == owner, "Only owner can withdraw funds");
require(amount <= balance, "Insufficient funds");
check that you are connected to correct network

Transaction Reverted even though I have a payable fallback function to receive eth, when I deploy without sending eth it works

Here is my code:
pragma solidity 0.8.6;
import "./Allowance.sol";
contract SharedWallet is Allowance {
event MoneySent(address indexed _beneficiary, uint _amount);
event MoneyReceived(address indexed _from, uint _amount);
function withdrawMoney(address payable _to, uint _amount) public ownerOrAllowed(_amount) {
require(_amount <= address(this).balance, "Contract doesn't own enough money");
if(!isOwner()) {
reduceAllowance(msg.sender, _amount);
}
emit MoneySent(_to, _amount);
_to.transfer(_amount);
}
function renounceOwnership() public override onlyOwner {
revert("can't renounceOwnership here"); //not possible with this smart contract
}
fallback () external payable {
emit MoneyReceived(msg.sender, msg.value);
}
}
Are you trying to send Ether to the contract as you deploy it? As I do not think you can do that easily. Well, there is a hacky way. Ethereum contract address is deterministic, i.e. knowing the creator's address and their nonce you can calculate the future address of your smart contract. And then send ETH to that address prior to deploying the contract.

How to make an API call in solidity?

I have a smart contract that I’m trying to make, it pays out the winners of my League of Legends tournament. However I’m running into an issue. I need to make an API call to get the winner of the match, I have a simple URL that I’ve make.
"example-winner.com/winner"
And it returns simple JSON with the address of the winner:
{"winner":"0xa7D0......."}
However, I’m not sure how to make the API call to the outside function. I know I need to use some sort of oracle technology.
Any thoughts? Below is my code:
pragma solidity ^0.4.24;
contract LeagueWinners{
address public manager;
address[] public players;
uint256 MINIMUM = 1000000000000000;
constructor() public{
manager = msg.sender;
}
function enter() public payable{
assert(msg.value > MINIMUM);
players.push(msg.sender);
}
function getWinner() public{
assert(msg.sender == manager);
// TODO
// Get the winner from the API call
result = 0; // the result of the API call
players[result].transfer(address(this).balance);
// returns an adress object
// all units of transfer are in wei
players = new address[](0);
// this empties the dynamic array
}
}
You can use Chainlink as your Oracle.
As many have mentioned, you will need an oracle to get your API call. Something that is important to note, your contract is actually asking an oracle to make your API call for you, and not making the API call itself. This is because the blockchain is deterministic. For more information see this thread.
To answer your question, you can use the decentralized oracle service Chainlink.
You'd add a function:
function getWinner()
public
onlyOwner
{
Chainlink.Request memory req = buildChainlinkRequest(JOB, address(this), this.fulfill.selector);
req.add("get", "example-winner.com/winner");
req.add("path", "winner");
sendChainlinkRequestTo(ORACLE, req, ORACLE_PAYMENT);
}
For the purpose of the following exmaple, we are going to pretend you want to return a uint256 instead of an address. You can return a bytes32 and then convert it to an address, but for simplicity let's say the API returns the index of the winner. You'll have to find a node and jobId that can make a http.get request and return a uint256 object. You can find nodes and jobs from market.link. Each testnet (Ropsten, Mainnet, Kovan, etc) has different node addresses, so make sure you pick the right ones.
For this demo, we are going to use LinkPool's ropsten node
address ORACLE=0x83F00b902cbf06E316C95F51cbEeD9D2572a349a;
bytes32 JOB= "c179a8180e034cf5a341488406c32827";
Ideally, you'd choose a number of nodes to run your job, to make it trustless and decentralized. You can read here for more information on precoordinators and aggregating data. disclosure I am the author of that blog
Your full contract would look like:
pragma solidity ^0.6.0;
import "github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";
contract GetData is ChainlinkClient {
uint256 indexOfWinner;
address public manager;
address payable[] public players;
uint256 MINIMUM = 1000000000000000;
// The address of an oracle
address ORACLE=0x83F00b902cbf06E316C95F51cbEeD9D2572a349a;
//bytes32 JOB= "93fedd3377a54d8dac6b4ceadd78ac34";
bytes32 JOB= "c179a8180e034cf5a341488406c32827";
uint256 ORACLE_PAYMENT = 1 * LINK;
constructor() public {
setPublicChainlinkToken();
manager = msg.sender;
}
function getWinnerAddress()
public
onlyOwner
{
Chainlink.Request memory req = buildChainlinkRequest(JOB, address(this), this.fulfill.selector);
req.add("get", "example-winner.com/winner");
req.add("path", "winner");
sendChainlinkRequestTo(ORACLE, req, ORACLE_PAYMENT);
}
// When the URL finishes, the response is routed to this function
function fulfill(bytes32 _requestId, uint256 _index)
public
recordChainlinkFulfillment(_requestId)
{
indexOfWinner = _index;
assert(msg.sender == manager);
players[indexOfWinner].transfer(address(this).balance);
players = new address payable[](0);
}
function enter() public payable{
assert(msg.value > MINIMUM);
players.push(msg.sender);
}
modifier onlyOwner() {
require(msg.sender == manager);
_;
}
// Allows the owner to withdraw their LINK on this contract
function withdrawLink() external onlyOwner() {
LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress());
require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer");
}
}
This would do about everything you need.
If you can't adjust the API to return a uint, you can return a bytes32 and then convert it to an address or a string.
function bytes32ToStr(bytes32 _bytes32) public pure returns (string memory) {
bytes memory bytesArray = new bytes(32);
for (uint256 i; i < 32; i++) {
bytesArray[i] = _bytes32[i];
}
return string(bytesArray);
}
You cannot. The vm does not have any I/O outside of the blockchain itself. Instead you will need to tell your smart contract who the winner is and then the smart contract can just read the value of that variable.
This design pattern is also known as the "oracle". Google "Ethereum oracle" for more info.
Basically your web server can call your smart contract. Your smart contract cannot call your web server. If you need your smart contract to access a 3rd party service then your web server will need to make the request then forward the result to solidity by calling a function in your smart contract.
You didn't properly explain what you are trying to do. Are you having trouble with the solidity code? or rather with your server? Here is an edited version. See if it helps.
pragma solidity ^0.4.24;
contract LeagueWinners{
address public manager;
//address[] public players;
uint256 MINIMUM = 1000000000000000;
constructor() public{
manager = msg.sender;
}
struct Player {
address playerAddress;
uint score;
}
Player[] public players;
// i prefer passing arguments this way
function enter(uint value) public payable{
assert(msg.value > MINIMUM);
players.push(Player(msg.sender, value));
}
//call this to get the address of winner
function winningPlayer() public view
returns (address winner)
{
uint winningScore = 0;
for (uint p = 0; p < players.length; p++) {
if (players[p].score > winningScore) {
winningScore = players[p].score;
winner = players[p].playerAddress;
}
}
}
// call this to transfer fund
function getWinner() public{
require(msg.sender == manager, "Only a manager is allowed to perform this operation");
// TODO
address winner = winningPlayer();
// Get the winner from the API call
//uint result = 0; // the result of the API call
winner.transfer(address(this).balance);
// returns an adress object
// all units of transfer are in wei
delete players;
// this empties the dynamic array
}
}
At least that is what I understand by your question.