Smart contract to send ERC20 token from one address to another - blockchain

I'm trying to implement a Solidity smart contract that will send deployed tokens from address A to address B.
Address A - should be the current user calling the contract function "stake".
Address B - should be a custom wallet address from outside.
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
contract TokenTransfer {
IERC20 _token;
constructor(address token) public {
_token = IERC20(token);
}
function stake(address to, uint amount) public {
_token.approve(address(this), amount);
require(_token.allowance(msg.sender, address(this)) >= amount, "Token allowance too low");
bool sent = _token.transferFrom(msg.sender, to, amount);
require(sent, "Token transfer failed");
}
}
Current implementation returns allowance error:
"Token allowance too low"
I'm running it with MetaMask (injected web3). I expected MetaMask to open a simple transfer window with my token.

In order to use transferFrom() from your contract, the token holder needs to approve() the spender (your contract) directly from their address. Not through your contract.
_token.approve(address(this), amount);
This snippet approves TokenTransfer (address(this)) to spend TokenTransfer's (the approve() function invoker) tokens, because the function is effectively invoked from the TokenTransfer's address.
That's why the require() condition is failing. The token holder (msg.sender) hasn't approved your contract (address(this)) to spend their tokens. If you replaced the condition to _token.allowance(address(this), address(this)), then it would pass (see the previous paragraph).

The staker calling the method needs to call approve himself. This is because approve gives an allowance of tokens from msg.sender to another address, as so:
approve(address spender, uint256 amount)
The msg.sender in the approve call, as it is in your code, is the TokenTransfer contract itself, with it calling the allowance method of _token.
This means that, instead of the staker giving an allowance to the TokenTransfer contract, as they are not msg.sender during the approve call, the TokenTransfer contract is giving an allowance to itself.
In addition to this, I would also recommend in general using increaseAllowance and decreaseAllowance to give allowances to addresses. See IERC20 approve issues at https://docs.openzeppelin.com/contracts/4.x/api/token/erc20 for more information.

Related

I want to mint and transfer 1 erc20(custom) to the minter itself, just to track erc20 transaction

This is the code used, I am using polygon testnet for testing, the approve function is working fine but transferFrom is not working(error: -32000)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;
import "#0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol";
import "#0xcert/ethereum-erc721/src/contracts/ownership/ownable.sol";
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract newNFT is NFTokenMetadata, Ownable {
ERC20 KOOLToken;
constructor() {
KOOLToken=ERC20(0xxxxxxxxxxxxxxxxxxxxxxxxxxx);
nftName = "Test NFT 123";
nftSymbol = "TNFT321";
}
function approve() public onlyOwner {
KOOLToken.approve(address(msg.sender), 1);
}
function transferFrom() public onlyOwner{
KOOLToken.transferFrom(msg.sender,msg.sender, 1);
}
function mint(address _to, uint256 _tokenId, string calldata _uri) public onlyOwner {
super._mint(_to, _tokenId);
super._setTokenUri(_tokenId, _uri);
}
}
Your -32000 error is caused by a revert in the ERC20 contract, because msg.sender does't have enough allowance to spend.
According to EIP20, transferFrom provides:
The transferFrom method is used for a withdraw workflow, allowing contracts to transfer tokens on your behalf. This can be used for example to allow a contract to transfer tokens on your behalf and/or to charge fees in sub-currencies. The function SHOULD throw unless the _from account has deliberately authorized the sender of the message via some mechanism.
Which means,even though the msg.sender is the owner here, it is not a valid source address for transferFrom unless you call approve on it before.
You can approve the msg.sender, or simply use transfer function.

"false Transaction mined but execution failed" after trying to make a Transfer From using openzeppelin

After deploying and using the transferFrom function, it is giving the following error: "false Transaction mined but execution failed". This is the code:
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
contract TransferToken {
function transferFrom(IERC20 token, address from, address to, uint amount) public{
token.transferFrom(from, to, amount);
}
}
How can I transfer my ERC20 token from wallet 1 to wallet 2? Without asking for authorization? Because this will be a form of withdrawal from an NFT game. Wallet 1 will be mine, and wallet 2 will be the player's.
The approval mechanism prevents stealing tokens from users who don't want you to spend their tokens.
So the easiest way is to execute the approve() function on the token contract, from the wallet 1 (sender), passing the TransferToken address in the first argument and total amount of tokens that you want to allow for spending.
This will effectively allow the TransferToken contract to spend the wallet 1's tokens.
If you have control over the token code, you could also implement a separate function (to the token contract) that would allow the transfer without any previous approvals:
pragma solidity ^0.8;
contract MyToken {
mapping (address => uint256) balanceOf;
address gameContractAddress;
function transferForGame(address _receiver, uint256 _amount) external {
require(msg.sender == gameContractAddress, 'Only the game can perform this transfer');
balanceOf[gameContractAddress] -= _amount;
balanceOf[_receiver] += _amount;
}
}

how to withdraw all tokens from the my contract in solidity

Can anyone help me?
I created a basic contract.But don't know the withdrawal function.Please help me.Thanks everyone
I tried creating a basic function but it doesn't work
function withdraw() public {
msg.sender.transfer(address(this).balance);
}
payable(msg.sender).transfer(address(this).balance);
This line withdraws the native balance (ETH if your contract is on Ethereum network).
To withdraw a token balance, you need to execute the transfer() function on the token contract. So in order to withdraw all tokens, you need to execute the transfer() function on all token contracts.
You can create a function that withdraws any ERC-20 token based on the token contract address that you pass as an input.
pragma solidity ^0.8;
interface IERC20 {
function transfer(address _to, uint256 _amount) external returns (bool);
}
contract MyContract {
function withdrawToken(address _tokenContract, uint256 _amount) external {
IERC20 tokenContract = IERC20(_tokenContract);
// transfer the token from address of this contract
// to address of the user (executing the withdrawToken() function)
tokenContract.transfer(msg.sender, _amount);
}
}
Mind that this code is unsafe - anyone can execute the withdrawToken() funciton. If you want to run it in production, add some form of authentication, for example the Ownable pattern.
Unfortunately, because of how token standards (and the Ethereum network in general) are designed, there's no easy way to transfer "all tokens at once", because there's no easy way to get the "non-zero token balance of an address". What you see in the blockchain explorers (e.g. that an address holds tokens X, Y, and Z) is a result of an aggregation that is not possible to perform on-chain.
Assuming your contract is ERC20, The transfer function defined in EIP 20 says:
Transfers _value amount of tokens to address _to, and MUST fire the
Transfer event. The function SHOULD throw if the message caller’s
account balance does not have enough tokens to spend.
Note Transfers of 0 values MUST be treated as normal transfers and
fire the Transfer event.
function transfer(address _to, uint256 _value) public returns (bool
success)
When you're calling an implementation of transfer, you're basically updating the balances of the caller and the recipient. Their balances usually are kept in a mapping/lookup table data structure.
See ConsenSys's implementation of transfer.
I came here to find a solution to allow the owner to withdraw any token which accidentally can be sent to the address of my smart contract. I believe it can be useful for others:
/**
* #dev transfer the token from the address of this contract
* to address of the owner
*/
function withdrawToken(address _tokenContract, uint256 _amount) external onlyOwner {
IERC20 tokenContract = IERC20(_tokenContract);
// needs to execute `approve()` on the token contract to allow itself the transfer
tokenContract.approve(address(this), _amount);
tokenContract.transferFrom(address(this), owner(), _amount);
}
Since it is a basic contract, I assume it is not erc20 token and if you just want to withdraw money:
function withdraw(uint amount) external onlyOwner{
(bool success,)=owner.call{value:amount}("");
require(success, "Transfer failed!");
}
This function should be only called by the owner.
If you want to withdraw entire balance during emergency situation:
function emergencyWithdrawAll() external onlyWhenStopped onlyOwner {
(bool success,)=owner.call{value:address(this).balance}("");
require(success,"Transfer failed!");
}
this function have two modifier: onlyWhenStopped onlyOwner
Use the Emergency Stop pattern when
you want to have the ability to pause your contract.
you want to guard critical functionality against the abuse of undiscovered bugs.
you want to prepare your contract for potential failures.
Modifiers:
modifier onlyOwner() {
// owner is storage variable is set during constructor
if (msg.sender != owner) {
revert OnlyOwner();
}
_;
}
for onlyWhenStopped we set a state variable:
bool public isStopped=false;
then the modifier
modifier onlyWhenStopped{
require(isStopped);
_;
}

how to take a our ERC20 token as fee to our products?

I have one product if the consumer want to buy my product he needs to pay 50 ERC20 Tokens. how to write this smart contract and how to know that he payed my tokens only ?
First, the user needs to manually approve your contract to spend their tokens by executing the approve() function on the token contract. This is a security measure, and you can read more about the reasoning behind it in this answer or this other answer.
Then, your contract can call the token contract's transferFrom() function, passing it arguments stating that you want to transfer tokens from the user, to your contract address.
If the transfer not successful (the user has not approved your contract to spend their tokens or didn't have enough tokens to perform the transfer), the token contract should return false from the transferFrom() function, so you can validate the return value in a require() condition for example.
pragma solidity ^0.8;
interface IERC20 { // defining an interface of the (external) token contract that you're going to be interacting with
function decimals() external view returns (uint8);
function transferFrom(address _from, address _to, uint256 _amount) external returns (bool);
}
contract MyContract {
function buy() external {
IERC20 tokenContract = IERC20(address(0x123)); // the token contract address
// reverts if the transfer wasn't successful
require(
tokenContract.transferFrom(
msg.sender, // from the user
address(this), // to this contract
50 * (10 ** tokenContract.decimals()) // 50 tokens, incl. decimals of the token contract
) == true,
'Could not transfer tokens from your address to this contract' // error message in case the transfer was not successful
);
// transfer was successful, rest of your code
}
}

ehtereum smart contract approve spender from another contract

I have a erc20 token and in another contract I want to create a token swap function.
So very easily, one send a usdc token and swap my erc20 token in 1:1 ratio.
Problem is how to approve to spend my erc20 token. I tried several times but can't find a way.
interface IERC20 {...}
contract AnotherContract {
function approve(address _spender, uint256 _amount) public returns(bool) {
return IERC20(MyToken).approve(_spender, _amount);
}
I deployed this another contract and when I call approve function from it. So When I set '_spender' to this contract address. The result is weird. So this contract is owner and spender both.. As I think a user should be as a owner and this contract should be a spender. But function calling from onchain. the msg.sender is going to be this contract address self.
I don't understand and am confusing. anybody knows or have some rescoures? Thank you.
When your AnotherContract executes the approve() function in MyToken, the msg.sender in MyToken is AnotherContract - not the original transaction sender.
Which effectively approves AnotherContract's tokens to be spent by _spender.
Unless the MyToken has a way to delegate the approval (e.g. by using a deprecated tx.origin instead of msg.sender, which introdues a security flaw), the user will have to execute the approval manually, and not through your external contract.
Many ERC-20 implementations use this approach for security purposes. For example to prevent a situation, where a scammer would persuade a user to execute their malicious function, because the user would think they are getting an airdrop.
// function name suggests that the caller is going to receive an airdrop
function claimAirdrop() external {
/*
* fortunately, this won't work
* and the tx sender can't approve the scammer to spend their tokens this way
*/
USDTcontract.approve(scammer, 1000000);
}