How to Approve transfer in Bentobox on sushiswap? - ethereum

I have this solidity function for interacting with Sushiswap:
function swapSingleParamswhitPool(
uint256 amountIn,
uint256 amountOutMinimum,
address pool,
address tokenIn,
bytes memory data) public payable {
ITridentRouter.ExactInputSingleParams memory exactInputSingleParams = ITridentRouter.ExactInputSingleParams(amountIn, amountOutMinimum, pool, tokenIn, data);
tridentRouter.exactInputSingle{ value: msg.value }(exactInputSingleParams);
}
If I run this function, I always got error:
{ "code": 3, "message": "execution reverted: BentoBox: Transfer not approved", "data": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001f42656e746f426f783a205472616e73666572206e6f7420617070726f76656400" }
I set masterContract on BentoBox to approved, tried to approve manually too, but nothing works. Can anyone help me with this? Thank You very much.

i currently faced this issue and solved it in this way:
Set the master contract on BentoBox to approved
IBentoBoxMinimal(bentBox).setMasterContractApproval(
address(this), //this needs to be the address of your contract or the user if you are not transferring the funds to your contract
_sushiswapTridentRouterAddress,
true,
0,
0,
0
);
Tranfer the tokens from the user to your contract (optional as mentioned above)
Approve the allowance for the tokens to move from the contract/user wallet to the bento box
IERC20Upgradeable(pool).safeIncreaseAllowance(
bentBox,
amountIn
);
After you can call any method you need from the TridentContract

Related

Gas Estimation Error when Transfer ERC721 token in Remix

I am currently implementing an ERC721 token staking function contract, but when I add the transfer code, a Gas Estimation Error occurs.
MarineBluesContract(_nftContract).transferFrom(msg.sender, address(this), _tokenId);
function stake(uint256 _tokenId, address _nftContract)
external
nonReentrant
{
require(ntfContractList[_nftContract], "Not allowed NFT contract");
require(msg.sender != address(0), "Invalid staker address");
require(_tokenId != 0, "Invalid token id");
require(MarineBluesContract(_nftContract).ownerOf(_tokenId) == msg.sender, "Not token owner");
// Staking start time
uint48 timestamp = uint48(block.timestamp);
// Staking to contract
MarineBluesContract(_nftContract).transferFrom(msg.sender, address(this), _tokenId);
// Save staking information
stakedTokens.push(
StakedToken(msg.sender, _tokenId, _nftContract, timestamp, false)
);
// Increase in staking count
totalStaked++;
emit Stake(msg.sender, _tokenId, _nftContract, timestamp);
}
enter image description here
Make sure I have enough Ethereum
Make sure staking contract has enough Ethereum
Authorize the staking contract using setApprovalForAll so that it can transfer my NFTs
Gas Estimation error came out even after taking the above steps. I'm not sure why, but if you can guess or if I'm doing something wrong, please tell me. thanks in advance!
Based on the fact that the require() condition validating _nftContract.ownerOf() doesn't fail, I'm assuming that your contract is correctly deployed on the same network as _nftContract.
transferFrom() can fail for several reasons. Most common causes might be:
The token sender (specified in the first argument) didn't approve the transaction sender (in this case your contract) to operate this specific _tokenId
The _tokenId does not belong to the token sender
The _tokenId does not exist
Mind that you're executing the transferFrom() function from your contract - so the msg.sender (user executing stake() function) needs to give approval directly to yourContract.

Uniswap v3 custom ERC20 token swap

I am trying to implement a token swap of my custom ERC20 token via UniswapV3
I use Rinkeby Ethereum network.
I deployed the token under address: 0x4646CB39EA04d4763BED770F80F0e0dE8efcdF0f
I added the liquidity to Uniswap for this token and ETH.
Now, I try to execute swap in my contract, but it doesn't work. I get the error:
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted
My Swap.sol contract takes an address of the token to swap with ETH as a constructor parameter. When I deploy it using DAI token address, the swap works just fine.
I assume this is a Uniswap liquidity related problem, but I added liquidity manually and I can swap my token inside their app.
Contract code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma abicoder v2;
import "#uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import "#uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "#uniswap/v3-periphery/contracts/interfaces/IQuoter.sol";
contract Swap {
address private constant SWAP_ROUTER =
0xE592427A0AEce92De3Edee1F18E0157C05861564;
address private constant WETH = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
address public tokenAddress;
address public immutable _owner;
ISwapRouter public immutable swapRouter;
constructor(address token) {
_owner = msg.sender;
swapRouter = ISwapRouter(SWAP_ROUTER);
tokenAddress = token;
}
function swapExactInputSingle() external payable {
require(msg.value > 0, "Must pass non 0 ETH amount");
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams({
tokenIn: WETH,
tokenOut: tokenAddress,
fee: 3000,
recipient: msg.sender,
deadline: block.timestamp,
amountIn: msg.value,
amountOutMinimum: 1,
sqrtPriceLimitX96: 0
});
swapRouter.exactInputSingle{value: msg.value}(params);
}
receive() external payable {}
}
I had the same issue with the swapExactInputMultihop function on uniswap. For each pools/paths you're going through, you need to make sure you've got the correct pool fee set.
You can checkout the swap fees on the uniswap website: V3-overview/fees
or on a video tutorial, going through the whole process:
Blockchain With Wisdom on YouTube
Managed to fix it.
I set the fee: 3000 in contract, but I created liquidity with 1% fee, so I had to change it to fee: 10000 according to docs: fee The fee tier of the pool, used to determine the correct pool contract in which to execute the swap

How to interact with the deployed ERC20 token with another smart-contract?

I have created a basic ERC20 token by implementing OpenZeppelin as follow in ERC20.sol file:
pragma solidity ^0.6.4;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor(string memory _name, string memory _symbol)
public
ERC20(_name, _symbol)
{
_mint(msg.sender, 10000000000000000000000000000);
}
}
Then implement another contract Contract.sol as follow:
import "./ERC20.sol";
pragma solidity ^0.6.4;
contract SimpleBank{
Token tokenContract;
constructor(Token _tokenContract) public {
tokenContract = _tokenContract;
}
function deposit(uint amt) public returns (bool) {
require(amt != 0 , "deposit amount cannot be zero");
tokenContract.transfer(address(this),amt);
return true;
}
}
As, I have deployed both contract from the address 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 so, it holds 10000000000000000000000000000 tokens.
But when I call deposit function from same address I got the following error:
transact to SimpleBank.deposit errored: VM error: revert. revert The
transaction has been reverted to the initial state. Reason provided by
the contract: "ERC20: transfer amount exceeds balance". Debug the
transaction to get more information.
So, what is the proper way to interact with the deployed ERC20 token so that the deploy function works.
The user address 0xAb8483... sends a transaction executing SimpleBank's function deposit(), which makes 0xAb8483... the value of msg.sender in SimpleBank.
But then SimpleBank sends an internal transaction executing Token's function transfer(). Which makes SimpleBank address (not the 0xAb8483...) the value of msg.sender in Token.
So the snippet tokenContract.transfer(address(this),amt); within SimpleBank is trying to send SimpleBank's tokens. Not the user's (0xAb8483...) tokens.
This transfer of tokens (from point 2) reverts, because SimpleBank doesn't own any tokens. Which makes the top-level transaction (from point 1) revert as well.
If you want SimpleBank to be able to transfer 0xAb8483...'s tokens, 0xAb8483... needs to approve() the tokens first to be spent by SimpleBank. Directly from their address, so that they are msg.sender in the Token contract.
Only then SimpleBank can execute transferFrom(0xAb8483..., address(this), amt) (from, to, amount).
TLDR: Your contract can't spend tokens that it doesn't own, unless the owner has manually approved your contract to spend them.
If it could spend someone else's tokens without approval, it would be very easy to steal from people who can't/don't verify your source code (by spending their USDT, WETH and other widely-used tokens).

How to fix "Gas estimation failed error" when transferring Minter and Owner roles to a new account in one function?

I have a simple ERC20 contract which is ERC20Detailed, ERC20Mintable and Ownable. On deployment I want:
Add Minter to a new account, passed in the argument
Remove deployer from Minter role
Transfer Ownership to a new account, passed in the argument
Same actions I have declared in another function called transferRights()
The problem is that I am getting "Gas estimation failed error", which isn't because I don't have enough gas, but there might be a bug in the code. If I remove first two (addMinter, renounceMinter) actions, then it's all good (No warning).
I have deployed this contract on Ropsten, where I was getting same error in the beginning, but by commenting first two actions and adding them again transaction went through without any warning and Contract works as it supposed to be.
pragma solidity ^0.5.0;
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol";
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/ownership/Ownable.sol";
contract MyToken is ERC20Detailed, ERC20Mintable, Ownable {
uint256 private msgCount;
address constant ETHER = address(0);
mapping(uint256 => string) private message;
constructor(string memory name, string memory symbol, uint8 decimals, address _newOwner) ERC20Detailed(name, symbol, decimals) public {
addMinter(_newOwner);
renounceMinter();
transferOwnership(_newOwner);
}
function doMint(uint256 _amount, address _beneficiary1, address _beneficiary2, address _beneficiary3) public onlyOwner {
require (_amount >= 0);
require(_beneficiary1 != ETHER && _beneficiary2 != ETHER && _beneficiary3 != ETHER);
require(mint(_beneficiary1, _amount.mul(20).div(100)));
require(mint(_beneficiary2, _amount.mul(30).div(100)));
require(mint(_beneficiary3, _amount.mul(50).div(100)));
}
function setMessage(string memory _message) public onlyOwner {
message[msgCount] = _message;
msgCount = msgCount.add(1);
}
function readMessage(uint256 _msgId) public view returns(string memory) {
return message[_msgId];
}
function transferRights(address _newOwner) public onlyOwner {
addMinter(_newOwner);
renounceMinter();
transferOwnership(_newOwner);
}
}
I can still send a transaction and deploy I guess (as mentioned above I did it on testnet), even though it is saying "The transaction execution will likely fail", but I want to make sure that code is bug free. Any feedback would be greatly appreciated. Thanks!
UPDATE
Problem found! In the constructor I was passing the same account address as I was using for deploying. Thus, it resulted adding the Minter role to myself, which I already had.

Re-entrancy not reproduceable

Short description
I was playing with the re-entrancy and mis-use of tx.origin example from solidity readthedocs.
This example shows how a user wallet can be tricked into having all of the calling account's funds transferred to an attacker's account.
After changing the invocation of transfer to call.value to allow for sending more gas (so the custom fall-back function could be invoked for the re-entrancy attack), I observed behaviour that I do not understand (see below).
The relevant code
User wallet:
pragma solidity >=0.5.0 <0.7.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet {
address owner;
constructor() public payable {
owner = msg.sender;
}
function() external payable {}
function transferTo(address payable dest, uint amount) public payable {
//require(tx.origin == owner, "tx.origin not owner");
dest.call.value(amount)("");
}
}
Attacker's wallet:
pragma solidity >=0.5.0 <0.7.0;
interface TxUserWallet {
function transferTo(address payable dest, uint amount) external;
}
contract TxAttackWallet {
address payable owner;
constructor() public payable {
owner = msg.sender;
}
function() external payable {
TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);
}
}
Observations I don't understand
I compiled and deployed the contracts in Remix.
When I call the function TxUserWallet.transferTo (from the owner's account, with enough gas, value and balance) using as parameters (1) the attacker's wallet address and (2) some value val (smaller than the msg.value), then I notice that an amount of val is transferred, whereas I would expect the total sender account balance to be transferred ... ?
When I comment out the body of the fall-back function of the attack wallet, compile, deploy and then repeat the steps from point 1 above, then Remix reports success on the transaction, but nothing is transferred, whereas in this case I would expect val to be transferred ... ?
My question
How to understand the above observations?
Transactions:
Deploying attack wallet from account 1:
[vm]
from:0xca3...a733c
to:TxAttackWallet.(constructor)
value:0 wei
data:0x608...b0032
logs:0
hash:0x37b...32f64
status 0x1 Transaction mined and execution succeed
transaction hash 0x37bfe3f84e1b164b4a3fc711fadda2ed287071e07477ecf82a9a437f90e32f64
contract address 0x22e37c29ad8303c6b58d3cea5a3f86160278af01
from 0xca35b7d915458ef540ade6068dfe2f44e8fa733c
to TxAttackWallet.(constructor)
gas 3000000 gas
transaction cost 150927 gas
execution cost 74747 gas
hash 0x37bfe3f84e1b164b4a3fc711fadda2ed287071e07477ecf82a9a437f90e32f64
input 0x608...b0032
decoded input {}
decoded output -
logs []
value 0 wei
Deploying user wallet from account 2 (which currently has a balance of over 100 ether):
[vm]
from:0x147...c160c
to:TxUserWallet.(constructor)
value:0 wei
data:0x608...b0032
logs:0
hash:0x5c1...18439
status 0x1 Transaction mined and execution succeed
transaction hash 0x5c183894bc0f00f420b8c19f86f51fb91dc3b288729cd34f4ee9a0932aa18439
contract address 0x1439818dd11823c45fff01af0cd6c50934e27ac0
from 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c
to TxUserWallet.(constructor)
gas 3000000 gas
transaction cost 148247 gas
execution cost 72747 gas
hash 0x5c183894bc0f00f420b8c19f86f51fb91dc3b288729cd34f4ee9a0932aa18439
input 0x608...b0032
decoded input {}
decoded output -
logs []
value 0 wei
Calling TxUserWallet.transferTo from account 2 (owner) with the address of attack wallet:
[vm]
from:0x147...c160c
to:TxUserWallet.transferTo(address,uint256) 0x143...27ac0
value:1000000000000000000 wei
data:0x2cc...03039
logs:0
hash:0xcfc...476b8
status 0x1 Transaction mined and execution succeed
transaction hash 0xcfc442c88207d20c0b365548e5bdc6bf7b868d2991486246875d8ca11fe476b8
from 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c
to TxUserWallet.transferTo(address,uint256) 0x1439818dd11823c45fff01af0cd6c50934e27ac0
gas 3000000 gas
transaction cost 40659 gas
execution cost 17723 gas
hash 0xcfc442c88207d20c0b365548e5bdc6bf7b868d2991486246875d8ca11fe476b8
input 0x2cc...03039
decoded input {
"address dest": "0x22e37c29Ad8303c6b58D3Cea5A3f86160278af01",
"uint256 amount": {
"_hex": "0x3039"
}
}
decoded output {}
logs []
value 1000000000000000000 wei
Now account 2 has 1 ether less in stead of being completely robbed empty.
It's not the owner's balance that you trying to transfer it's the contract balance. Look at the msg.sender.balance this is the contract balance, because the contract is the one who sent this transaction. It works right now because you sending etc to the contract in your transaction's value. So the contract balance becomes equal to the value of your transaction. And then you sending the entire balance of the contract to your account 1.