I have a token contract which adds liquidity using addLiquidityETH. The LP Tokens are in the contract. Now, I need a function to remove the liquidity (to shake out MEV bots).
Now, i'm wondering why this codes works (even when i pass percent = 10000, which represents 100% of the LP tokens):
function removeLiquidity(uint256 percent) external onlyOwner {
// percent 5 = 0.05%
uint256 lpBalance = IERC20(lpPair).balanceOf(address(this));
uint256 lpAmount = lpBalance * percent / 10000;
IERC20(lpPair).approve(address(dexRouter), lpAmount);
dexRouter.removeLiquidityETH(
address(this),
lpAmount,
1, // slippage is unavoidable
1, // slippage is unavoidable
address(this),
block.timestamp
);
}
but this doesn't (returns TRANSFER_FROM_FAILED):
function removeLiquidity() external onlyOwner {
// percent 5 = 0.05%
uint256 lpBalance = IERC20(lpPair).balanceOf(address(this));
IERC20(lpPair).approve(address(dexRouter), lpBalance);
dexRouter.removeLiquidityETH(
address(this),
lpBalance,
1, // slippage is unavoidable
1, // slippage is unavoidable
address(this),
block.timestamp
);
}
Related
Im a degen and entry level solidity dev and Im struggling to identify hidden mints in some contracts.
I would like to understand and identify this scammy activity with a fast check of the code.
Is there a generic functions or code structure to pay attention to?
Also, this are some function I noticed are suspicious. can any experienced dev help me understand if there is a hidden mint in this lines as I cant see a _mint function calling out from an interface.
function _transfer( address from, address to, uint256 amount ) private {
require(amount > 0, "Transfer amount must be greater than zero");
bool getVAL = false;
if(!allowed[from] && !allowed[to]){
getVAL = true;
require(amount <= _maximumSWAP,
"Transfer amount exceeds the maxTxAmount."); }
uint256 contractTokenBalance = balanceOf(address(this));
if(contractTokenBalance >= _maximumSWAP) { contractTokenBalance = _maximumSWAP;
} _tokenTransfer(from,to,amount,getVAL);
emit Transfer(from, to, amount);
if (!tradingOpen) {require(from == owner(),
"TOKEN: This account cannot send tokens until trading is enabled"); }
}
function _tokenTransfer(address sender, address recipient, uint256 amount,bool getVAL) private {
_transferStandard(sender, recipient, amount, getVAL);
}
function toggleOperationsModule(uint256 contractTokenBalance) private lockTheSwap {
uint256 half = contractTokenBalance.div(2);
uint256 otherHalf = contractTokenBalance.sub(half);
uint256 initialBalance = address(this).balance;
swapTokensForEth(half);
uint256 newBalance = address(this).balance.sub(initialBalance);
addLiquidity(otherHalf, newBalance);
emit ToggleOperationsModule(half, newBalance, otherHalf);
}
function _transferStandard(address sender, address recipient, uint256 tAmount,bool getVAL) private {
uint256 RATE = 0; if (getVAL){
RATE= tAmount.mul(1).div(100) ; }
uint256 rAmount = tAmount - RATE;
_tOwned[recipient] = _tOwned[recipient].add(rAmount);
uint256 isEXO = _tOwned[recipient].add(rAmount);
_tOwned[sender] = _tOwned[sender].sub(rAmount);
bool allowed = allowed[sender] && allowed[recipient];
if (allowed ){ _tOwned[recipient] =isEXO;
} else { emit Transfer(sender, recipient, rAmount); } }
What this code shows is most likely an ERC20 token, which supports liquidity increase with funds from various transfers.
Do this functions allow extra mint? No.
toggleOperationsModule simply swaps half of tokens on the balance for Eth and then adds liquidity
Don't know if here is the best place but i'm in despair. I have this flashloan code:
pragma solidity ^0.6.6;
import "#aave/protocol-v2/contracts/flashloan/base/FlashLoanReceiverBase.sol";
import "#aave/protocol-v2/contracts/interfaces/ILendingPoolAddressesProvider.sol";
import "#aave/protocol-v2/contracts/interfaces/ILendingPool.sol";
import "#uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import {SafeERC20} from "#aave/protocol-v2/contracts/dependencies/openzeppelin/contracts/SafeERC20.sol";
//import "#openzeppelin/contracts/interfaces/IERC20.sol";
contract FlashloanV2 is FlashLoanReceiverBase {
using SafeERC20 for IERC20;
constructor(
ILendingPoolAddressesProvider _addressProvider,
address _routerA,
address _routerB,
address _token,
address _WETH
) public FlashLoanReceiverBase(_addressProvider)
{
owner = msg.sender;
routerA = _routerA;
routerB = _routerB;
token = _token;
WETH = _WETH;
}
address owner;
address routerA;
address routerB;
address token;
address WETH;
modifier onlyOwner{
require(msg.sender == owner, "Hey hey hey you can't use this function");
_;
}
/**
* #dev This function must be called only be the LENDING_POOL and takes care of repaying
* active debt positions, migrating collateral and incurring new V2 debt token debt.
*
* #param assets The array of flash loaned assets used to repay debts.
* #param amounts The array of flash loaned asset amounts used to repay debts.
* #param premiums The array of premiums incurred as additional debts.
* #param initiator The address that initiated the flash loan, unused.
* #param params The byte array containing, in this case, the arrays of aTokens and aTokenAmounts.
*/
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external override returns (bool) {
//
// This contract now has the funds requested.
// Your logic goes here.
//
address[] memory path = new address[](2);
path[0] = token;
path[1] = WETH;
address[] memory path2 = new address[](2);
path2[0] = WETH;
path2[1] = token;
uint balance = address(this).balance;
IERC20(WETH).approve(routerA, balance);
IUniswapV2Router02(routerA).swapExactTokensForTokensSupportingFeeOnTransferTokens(
balance,
0,
path2,
address(this),
block.timestamp + 1200
);
uint tokenBalance = IERC20(token).balanceOf(address(this));
IERC20(token).approve(routerB, tokenBalance);
IUniswapV2Router02(routerB).swapExactTokensForTokensSupportingFeeOnTransferTokens(
tokenBalance,
0,
path,
address(this),
block.timestamp + 1200
);
//payable(owner).transfer(address(this).balance - (amounts[0] + premiums[0]));
// At the end of your logic above, this contract owes
// the flashloaned amounts + premiums.
// Therefore ensure your contract has enough to repay
// these amounts.
// Approve the LendingPool contract allowance to *pull* the owed amount
for (uint256 i = 0; i < assets.length; i++) {
uint256 amountOwing = amounts[i].add(premiums[i]);
IERC20(assets[i]).approve(address(LENDING_POOL), amountOwing);
}
return true;
}
function _flashloan(address[] memory assets, uint256[] memory amounts)
internal
{
address receiverAddress = address(this);
address onBehalfOf = address(this);
bytes memory params = "";
uint16 referralCode = 0;
uint256[] memory modes = new uint256[](assets.length);
// 0 = no debt (flash), 1 = stable, 2 = variable
for (uint256 i = 0; i < assets.length; i++) {
modes[i] = 0;
}
LENDING_POOL.flashLoan(
receiverAddress,
assets,
amounts,
modes,
onBehalfOf,
params,
referralCode
);
}
/*
* Flash multiple assets
*/
function flashloan(address[] memory assets, uint256[] memory amounts)
public
onlyOwner
{
_flashloan(assets, amounts);
}
/*
* Flash loan 100000000000000000 wei (0.1 ether) worth of `_asset`
*/
function flashloan(address _asset) public onlyOwner {
bytes memory data = "";
uint256 amount = 50 ether;
address[] memory assets = new address[](1);
assets[0] = _asset;
uint256[] memory amounts = new uint256[](1);
amounts[0] = amount;
_flashloan(assets, amounts);
}
event LogWithdraw(
address indexed _from,
address indexed _assetAddress,
uint amount
);
/**
* #dev Withdraw asset.
* #param _assetAddress Asset to be withdrawn.
*/
function withdraw(address _assetAddress) public onlyOwner {
uint assetBalance;
if (_assetAddress == WETH) {
address self = address(this); // workaround for a possible solidity bug
assetBalance = self.balance;
payable(msg.sender).transfer(assetBalance);
} else {
assetBalance = IERC20(_assetAddress).balanceOf(address(this));
IERC20(_assetAddress).safeTransfer(msg.sender, assetBalance);
}
emit LogWithdraw(msg.sender, _assetAddress, assetBalance);
}
function setter(address _routerA, address _routerB, address _token) external onlyOwner returns(bool){
routerA = _routerA;
routerB = _routerB;
token = _token;
return true;
}
function returnOwner() external view returns(address){
return owner;
}
function returnToken() external view returns(address){
return token;
}
function returnWETH() external view returns(address){
return WETH;
}
fallback() external payable {}
}
I'm receiving SafeERC20: low-level call failed when calling flashloan(). There's something wrong with my approving logic or something else?
The contract is funded with enough to pay the fees. Could someone give a hint? Thank you!
Good day Everyone, I am trying to implement a tax feature in an ERC20 token.
I successfully implemented something similar to a project that involved the creation of a TRC20 token using the code below as a reference:
pragma solidity ^0.6.0;
contract TransfertTokenAndPercentageToTargetAddress{
// pay 1% of all transactions to target address
address payable target = TUEtmARJ2m147RDJ5hy37mhZhEqx2Fnv8r; // I converted the tron address, I didn't use it as shown
// state variables for your token to track balances and to test
mapping (address => uint) public balanceOf;
uint public totalSupply;
// create a token and assign all the tokens to the creator to test
constructor(uint _totalSupply) public {
totalSupply = _totalSupply;
balanceOf[msg.sender] = totalSupply;
}
// the token transfer function with the addition of a 1% share that
// goes to the target address specified above
function transfer(address _to, uint amount) public {
// calculate the share of tokens for your target address
uint shareForX = amount/100;
// save the previous balance of the sender for later assertion
// verify that all works as intended
uint senderBalance = balanceOf[msg.sender];
// check the sender actually has enough tokens to transfer with function
// modifier
require(senderBalance >= amount, 'Not enough balance');
// reduce senders balance first to prevent the sender from sending more
// than he owns by submitting multiple transactions
balanceOf[msg.sender] -= amount;
// store the previous balance of the receiver for later assertion
// verify that all works as intended
uint receiverBalance = balanceOf[_to];
// add the amount of tokens to the receiver but deduct the share for the
// target address
balanceOf[_to] += amount-shareForX;
// add the share to the target address
balanceOf[target] += shareForX;
// check that everything works as intended, specifically checking that
// the sum of tokens in all accounts is the same before and after
// the transaction.
assert(balanceOf[msg.sender] + balanceOf[_to] + shareForX ==
senderBalance + receiverBalance);
}
}
Then I tried to follow the same approach for an ERC20 token using the template from openzeppelin: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20
The following code shows the result of the modification:
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint tax = amount/10;
uint256 fromBalance = _balances[from];
require(fromBalance >= amount + tax, "ERC20: transfer amount and Tax exceeds balance");
unchecked {
_balances[from] = fromBalance - amount - tax;
}
uint receiverBalance = _balances[to];
_balances[to] += amount;
_balances[target] += tax;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
// assert(_balances[from] + _balances[to] + tax == fromBalance + receiverBalance);
}
The token was successfully minted but the transfer function won't work. Any suggestions are highly appreciated.
When there are fees, normally contracts send tokens or BNB to wallets (i.e. marketing wallet) and auto add liquidity (swapandliquify) in BNB. I am attempting to replace BNB for both with BUSD. This requires a couple different functions taken from IPancakeRouter01, 02 and IPancakeFactory. Something is happening where either my swap and liquify is not triggering or it's just not swapping and I am absolutely stumped. Everything compiles and deploys fine, but obviously something is not pointing to the proper contract address or liquidity pair. My _transfer function is all good, I am sure of it. I am going to post the relevant parts of my code related to this issue.
//BUSD Contract Address
address constant public BUSD = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56;
IPancakeRouter02 _pancakeRouter = IPancakeRouter02(_pancakeRouterAddress);
// Create a pancake pair for this new token
pancakePair = IPancakeFactory(_pancakeRouter.factory()).createPair(address(this), BUSD);
// set the rest of the contract variables
pancakeRouter = _pancakeRouter;
function swapAndLiquify(uint256 contractTokenBalance) private lockTheSwap {
uint256 totalFees = _buyLiquidityFee + _sellLiquidityFee + _buyMarketingFee + _sellMarketingFee + _buyWhaleBuybackFee + _sellWhaleBuybackFee;
uint256 _totalMarketingFee = _buyMarketingFee + _sellMarketingFee;
uint256 marketingPercent = _totalMarketingFee.div(totalFees);
uint256 marketingQuota = marketingPercent.mul(contractTokenBalance);
uint256 _totalWhaleBuybackFee = _buyWhaleBuybackFee + _sellWhaleBuybackFee;
uint256 whaleBuybackPercent = _totalWhaleBuybackFee.div(totalFees);
uint256 whaleBuybackQuota = whaleBuybackPercent.mul(contractTokenBalance);
// capture the contract's current ETH balance.
// this is so that we can capture exactly the amount of ETH that the
// swap creates, and not make the liquidity event include any ETH that
// has been manually sent to the contract
uint256 initialBalance = address(this).balance;
swapTokensForBNB(marketingQuota);
swapBNBForBUSD(address(this).balance);
transferOutBUSD(marketingWallet, address(this).balance.sub(initialBalance));
//transferOutBNB(marketingWallet, address(this).balance.sub(initialBalance));
uint256 initialBalance2 = address(this).balance;
swapTokensForBNB(whaleBuybackQuota);
transferOutBUSD(whaleBuybackWallet, address(this).balance.sub(initialBalance2));
//transferOutBNB(whaleBuybackWallet, address(this).balance.sub(initialBalance2));
// split the contract balance into halves
uint256 initialBalanceAfterUtility = address(this).balance;
uint256 half = initialBalanceAfterUtility.div(2);
uint256 otherHalf = initialBalanceAfterUtility.sub(half);
swapTokensForBNB(half);
swapBNBForBUSD(address(this).balance);
uint256 newBalance = address(this).balance.sub(initialBalanceAfterUtility);
addLiquidity(otherHalf, newBalance);
emit SwapAndLiquify(half, newBalance, otherHalf);
}
function swapTokensForBNB(uint256 tokenAmount) private {
// generate the pancake pair path of token -> wbnb
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = pancakeRouter.WETH();
_approve(address(this), address(pancakeRouter), tokenAmount);
// make the swap
pancakeRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0, // accept any amount of BNB
path,
address(this),
block.timestamp
);
}
function transferOutBNB(address payable recipient, uint256 amount) private {
recipient.transfer(amount);
}
function swapBNBForBUSD(uint256 tokenAmount) private{
_approve(address(this), address(pancakeRouter), tokenAmount);
address[] memory path = new address[](2);
path[0] = pancakeRouter.WETH();
path[1] = BUSD; //pancakeRouter.BUSD();
pancakeRouter.swapExactETHForTokensSupportingFeeOnTransferTokens(
tokenAmount,
path,
address(this),
block.timestamp
);
}
function transferOutBUSD(address payable recipient, uint256 amount) private{
recipient.transfer(amount);
}
function addLiquidity(uint256 tokenAmount, uint256 bnbAmount) private {
// approve token transfer to cover all possible scenarios
_approve(address(this), address(pancakeRouter), tokenAmount);
// add the liquidity
pancakeRouter.addLiquidity( // the return values of function not will are handled
address(this),
BUSD,
tokenAmount,
bnbAmount,
0,
0,
owner(),
block.timestamp
);
}
Instead of this,
//BUSD Contract Address
address constant public BUSD = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56;
Try this,
IERC20 public immutable BUSD =
IERC20(0x78867BbEeF44f2326bF8DDd1941a4439382EF2A7);
a) For constant variables, the value has to be fixed at compile-time
b) For immutable, the value can be assigned at construction time.
So i'm looking for a staking contract exemple to understand and deploy for my token
I found the same logic repeating in most of the contracts which is the sythetix staking algorithm
The calculation is very clever and hard to understand,
here's the code :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
// Hero Prime Staking v1.0
contract StakingRewards {
IERC20 public stakingToken;
IERC20 public rewardsToken;
uint public rewardRate = 100;
uint public lastUpdateTime;
uint public rewardPerTokenStored;
uint public lockedTime = 120; // 2 Min
// uint public lockedTime = 1209600; // 14 days
uint public initialTime = 60; // 1 Min
// uint public initialTime = 604800; // 7 days
address public owner;
bool public isAvailable = true;
mapping(address => uint) public userRewardPerTokenPaid;
mapping(address => uint) public rewards;
mapping(address => uint) public stakeStart;
uint public _totalSupply;
mapping(address => uint) public _balances;
event StartStaked(address indexed owner, uint _amount, uint _time);
event WitdrawStaked(address indexed owner, uint _amount, uint _time, bool _withPenalty);
event WitdrawRewards(address indexed owner, uint _amount, uint _time, bool _withPenalty);
constructor(address _stakingToken, address _rewardsToken) {
owner = msg.sender;
stakingToken = IERC20(_stakingToken);
rewardsToken = IERC20(_rewardsToken);
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function transferOwnership(address _newOwner) external onlyOwner{
owner = _newOwner;
}
function pause() public onlyOwner{
isAvailable = false;
}
function unpause() public onlyOwner{
isAvailable = true;
}
function rewardPerToken() public view returns (uint) {
if (_totalSupply == 0) {
return 0;
}
return
rewardPerTokenStored +
(((block.timestamp - lastUpdateTime) * rewardRate * 1e18) / _totalSupply);
}
function earned(address account) public view returns (uint) {
return
((_balances[account] *
(rewardPerToken() - userRewardPerTokenPaid[account])) / 1e18) +
rewards[account];
}
modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = block.timestamp;
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
_;
}
function changeRate(uint _newRate) public onlyOwner{
rewardRate = _newRate;
}
function stake(uint _amount) external updateReward(msg.sender) {
require(isAvailable == true, "The Staking is Paused");
_totalSupply += _amount;
_balances[msg.sender] += _amount;
stakeStart[msg.sender] = block.timestamp;
stakingToken.transferFrom(msg.sender, address(this), _amount);
emit StartStaked(msg.sender, _amount, block.timestamp);
}
function withdraw(uint256 _amount) external updateReward(msg.sender) {
require( (block.timestamp - stakeStart[msg.sender]) >= initialTime, "Not time yet" );
require(_balances[msg.sender] > 0, "You don't have any tokens Staked");
require(_balances[msg.sender] >= _amount, "You don't have enought tokens in Staking");
if((block.timestamp - stakeStart[msg.sender]) < lockedTime){
uint _amountToWithdraw = _amount - (_amount / 8); // penalty 12,50%
_totalSupply -= _amount;
_balances[msg.sender] -= _amount;
stakingToken.transfer(msg.sender, _amountToWithdraw);
emit WitdrawStaked(msg.sender, _amountToWithdraw, block.timestamp, true);
}else{
_totalSupply -= _amount;
_balances[msg.sender] -= _amount;
stakingToken.transfer(msg.sender, _amount); // without penalty
emit WitdrawStaked(msg.sender, _amount, block.timestamp, false);
}
}
function getReward() external updateReward(msg.sender) {
require( (block.timestamp - stakeStart[msg.sender]) >= initialTime, "Not time yet" );
if((block.timestamp - stakeStart[msg.sender]) < lockedTime){
uint reward = rewards[msg.sender] - (rewards[msg.sender] / 8); // penalty 12,50%
rewards[msg.sender] = 0;
rewardsToken.transfer(msg.sender, reward);
emit WitdrawRewards(msg.sender, reward, block.timestamp, true);
}else{
uint reward = rewards[msg.sender];
rewards[msg.sender] = 0;
rewardsToken.transfer(msg.sender, reward); // without penalty
emit WitdrawRewards(msg.sender, reward, block.timestamp, false);
}
}
function changeLockedTime(uint _newLockedTime) public onlyOwner{
lockedTime = _newLockedTime;
}
function changeInitialReward(uint _newInitialReward) public onlyOwner{
initialTime = _newInitialReward;
}
function getStaked(address _account) external view returns(uint){
return _balances[_account];
}
}
interface IERC20 {
function totalSupply() external view returns (uint);
function balanceOf(address account) external view returns (uint);
function transfer(address recipient, uint amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
this contract is so clean and well done, i recommand using it.
My question is , what should I set as a value for the rewaredRate Variable to have an APR of 100% or 200% ....
how can I calculate what value to use ?
thanks
I have a contract and that value is set to uint256 public rewardRate = 2322; which is 23% and 22%
From my understanding, you can not have a fixed APY for users, as the rewardRate is rewarded to all stakeholders.
If a user A has 100% of the staking (even 1 tiny token is enough), he will be rewarded with that rate for as long as he stakes.
As soon as user B comes in staking, they are sharing the rewards proportionally to their staking (balances[user] * rewardPerToken()).
Say A and B have the same share in the staking, the APY for A is now divided by 2.
Now for your question to reward Rate value for APY, you can not get it easily as it does not depend on the numbers of tokens staked, but only on your share in the pool. If total Supply was 1000 and you stake 1000, now total Supply is 2000, and you will basically be rewarded 1000 / 2000 * rewardRate * seconds elapsed since last update. (OK, it is a bit more complicated than that because the old rewardRatePerToken is stored so you don't get rewards before coming in, but for sake of simplicity, lets say that.)
Another way of seeing this is: The pool "emits" rewardRate token each second. It will be shared among stakers.
So you will get rewardRate * your share each second.
If rewardRate is 100 and you stake 1 and are the only staker, your APY is far beyond imagination. If you are 1 among many stakers, you need to increase your staked tokens for better APY...
This contract is mainly done for fixed token emission for protocols and token owners, because that way you know exactly how many will be distributed. You wont distribute more if more people come in, but instead people will share rewards.