How to transfer ERC20 tokens to another address using solidity? - solidity

I create ERC20 tokens, and i want to transfer my tokens to another address.
I have two accounts in my metamask.(Account A/B)
My ERC20 code's here (I deployed and save tokens in account A)
pragma solidity ^0.8.0;
// SPDX-License-Identifier: MIT
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(string memory name, string memory symbol) ERC20(name,symbol) {
// mint 1000 token
_mint(msg.sender, 1000*10**uint(decimals()));
}
}
Question : how can I transfer my ERC20 tokens from the current address to another? (A->B)
I use this code in account A, but not work.
pragma solidity ^0.8.7;
// SPDX-License-Identifier: MIT
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
contract TokenTransfer {
IERC20 _token;
// token = MyToken's contract address
constructor(address token) public {
_token = IERC20(token);
}
// to = Account B's address
function stake(address to, uint amount) public {
_token.approve(address(this), amount);
require(_token.allowance(address(this), address(this)) >= amount);
_token.transferFrom(msg.sender, to, amount);
}
}
error message
transact to TokenTransfer.stake errored: Internal JSON-RPC error.
{
"code": 3,
"message": "execution reverted: ERC20: insufficient allowance",
"data": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001d45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000"
}
how to fix it?

Your logic is wrong!
If you want to send a token from account A to account B without passing from smart contract, you can use 'Send' options available in Metamask and other wallet.
If you want use a smart contract, your logic change.
In your smart contract code, there are some errors:
_token.approve(address(this), amount): when you write this statement, you're approving smart contract itself to move your tokens but it doesn't have any token! Another thing about approve() function. This operation must be do from user, in details a person must to give to smart contract permission accessing about his wallet;
Another error is: smart contract cannot failt to have a function about deposit token to call from account A. In this case, when you write this statament, _token.transferFrom(msg.sender, to, amount);, (msg.sender is smart contract) you cannot transfer any amount to receiver address because smart contract doesn't have the amount of tokens.
Last problem, is when you transfer a token from smart contract to address you must use transfer() function instead transferFrom() because this last function require approve + transfer and smart contracts cannot approve itself. While transfer() is used only transfer funds.
To resolve this problems, you can see this smart contract code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
contract TokenTransfer {
IERC20 _token;
// token = MyToken's contract address
constructor(address token) {
_token = IERC20(token);
}
// Modifier to check token allowance
modifier checkAllowance(uint amount) {
require(_token.allowance(msg.sender, address(this)) >= amount, "Error");
_;
}
// In your case, Account A must to call this function and then deposit an amount of tokens
function depositTokens(uint _amount) public checkAllowance(_amount) {
_token.transferFrom(msg.sender, address(this), _amount);
}
// to = Account B's address
function stake(address to, uint amount) public {
_token.transfer(to, amount);
}
// Allow you to show how many tokens owns this smart contract
function getSmartContractBalance() external view returns(uint) {
return _token.balanceOf(address(this));
}
}

Related

how to make onRecivedERC20 function?

I would like to make a function for receiving ERC20 in contract and after receiving ERC20 token it should transfer that ERC20 to another wallet.
the flow should be if a user uses that function first it should send that ERC20 to the contract and after that contract should forward that token to another wallet. I don't know where to start from
example transaction is this:
https://polygonscan.com/tx/0x88d85e4b746b65708a38b8f4c5d5bc0f73ff78e28868084eed565976b46df10e
The ERC-20 standard doesn't define how to notify a receiver contract about the incoming transfer. So you'll need to use either another standard (e.g. ERC-777) or build a custom notification hook.
Here's an example of such custom notification. It builds on top of the OpenZeppelin ERC-20 implementation, checks if the receiver is a contract - and if it is a contract, tries to call its onERC20Receive() function.
You can test it by deploying two separate contracts - MyToken and SomeReceiver - and then sending tokens from the deployer address to SomeReceiver. You can see that the ReceivedTokens event was emitted, as a result of invoking the function onERC20Receive when SomeReceiver received the tokens.
pragma solidity ^0.8.16;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor() ERC20("MyToken", "MyT") {
_mint(msg.sender, 1000 * 1e18);
}
function _afterTokenTransfer(address from, address to, uint256 amount) internal override {
if (to.code.length > 0) {
// token recipient is a contract, notify them
try IERC20Receiver(to).onERC20Receive(from, amount) returns (bool success) {
// the recipient returned a bool, TODO validate if they returned true
} catch {
// the notification failed (maybe they don't implement the `IERC20Receiver` interface?)
}
}
}
}
interface IERC20Receiver {
function onERC20Receive(address from, uint256 amount) external returns (bool);
}
contract SomeReceiver is IERC20Receiver {
event ReceivedTokens(address from, uint256 amount);
function onERC20Receive(address from, uint256 amount) external returns (bool) {
emit ReceivedTokens(from, amount);
return true;
}
}

Smart Contract Withdrawal from contract owner

For example I don't want to store ETH on Smart Contract but to the contract owner. Then how to implement withdrawal from the contract owner?
pragma solidity ^0.8.7;
contract WDfromContractOwner {
address public owner;
constructor() {
owner=msg.sender;
}
function deposit() external payable returns (bool) {
payable(owner).transfer(msg.value);
return true;
}
function withdrawal() external returns (bool) {
// Witdrawal from owner address....???
return true;
}
}
A smart contract is not able to pull ETH from an address (other than the address sending the ETH to the contract). The transfer needs to always be originated from and signed by the sender (in your case the owner).
However, it can pull tokens owned by an address. The sender (owner) needs to approve() the amount at first, interacting with the token contract from their address. Then your contract can invoke the token's transferFrom() function.
pragma solidity ^0.8;
interface IERC20 {
function transferFrom(address, address, uint256) external returns (bool);
}
contract WDfromContractOwner {
address public owner;
function withdrawToken() external {
// Only reachable from the mainnet.
// Transfers from other networks (such as Remix VM) will fail.
address mainnetUSDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address receiver = msg.sender; // address of the user executing the `withdrawToken()`
uint256 amount = 5 * 1e6; // 5 USDT, 6 decimals
require(
// the `owner` needs to execute `approve()` on the token contract directly from the `owner` address
// so that the `WDfromContractOwner` contract can spend their tokens
IERC20(mainnetUSDT).transferFrom(owner, receiver, amount)
);
}
}
You can get the approved amount using web3.js:
const USDTAddress = "0xdAC17F958D2ee523a2206206994597C13D831ec7";
const ownerAddress = "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF";
// just the `balanceOf()` is sufficient in this case
const ABI = [
{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}
];
const USDTContract = new web3.eth.Contract(ABI, USDTAddress);
const approved = await USDTContract.methods.balanceOf(ownerAddress).call();
console.log(approved);
If you are already are transferring the funds to the owner each time an user deposit it should not be necessary, but if you want you could do it anyway, you have different options like passing the amount as a parameter, have a default or a minimum amount, etc, but for simplicity to withdraw all the funds just add this two lines in the function
(bool result,)= payable(owner).call{value: address(this).balance }("");
return result

Solidity calling contract with elevated permissions

I have two contracts, one for handling staking and one for minting a NFT. The flow I want is for the user to stake in frontend react app which will invoke the staking contract. The user will then be eligible to mint a NFT when staked.
Now the issue I am facing is that because the minting role is called from stakingExample contract, which requires the user to invoke this, but as it has a critical function (mint) of the other contract, it should be protected with permissions such that only StakingExample can call NFTExample contract.
Is there a way to allow the user to run NFTExample with elevated permissions temporary in smart contract?
Example of staking contract:
// SPDX-License-Identifier: unlicensed
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/access/AccessControl.sol";
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
import "#openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract StakingExample is AccessControl {
bytes32 public constant CONTRACT_ROLE = keccak256("CONTRACT_ROLE");
NFTExample public _NFTExample;
...
function someStakingFunction() {
// code that stakes and
// set some variable that tracks if user have minted
}
function claimNFT(uint256 _pid, string memory _tokenURI) public onlyRole(CONTRACT_ROLE) {
// checks if user have unclaimed NFT
if (haveUnclaimed) {
_NFTExample.mintItem(msg.sender, _tokenURI)
}
}
}
Example of NFT contract:
// SPDX-License-Identifier: unlicensed
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/access/AccessControl.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract CMRGachaSeedNFT is ERC721URIStorage, AccessControl, ERC721Enumerable {
bytes32 public constant CONTRACT_ROLE = keccak256("CONTRACT_ROLE");
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
...
// Only Contract Role can call mint item, which mint item and transfers it to user's address
function mintItem(address _address, string memory _tokenURI)
public
onlyRole(CONTRACT_ROLE)
returns (uint256)
{
// Do some checks
// Mint
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(_address, newItemId);
_setTokenURI(newItemId, _tokenURI);
return newItemId;
}
}
You need to add one function in staking contract which shows amount of the staking:
function showStakeAmount() external view returns(uint256){
//I don't know your codes about this but you need a mapping to store
//the stake amount of each user and here you return it but something like this:
return StakingAmountOfUsers(msg.sender);
}
Then you need an interface of the staking contract and its address, also make an modifier in NFT contract (Following changes must be added):
interface StakingInterface{
function showStakeAmount() external view returns(uint256);
}
contract CMRGachaSeedNFT is ERC721URIStorage, AccessControl, ERC721Enumerable {
uint256 AmountThatShouldBeStaked;
StakingInterface StakingContract;
constructor(address STAKING_CONTRACT_ADDRESS){
StakingContract = StakingInterface(STAKING_CONTRACT_ADDRESS);
}
modifier isStaked(){
require(StakingContract.showStakeAmount() > AmountThatShouldBeStaked, "You did not stake enough amount of X token");
_;
}
function mintItem(address _address, string memory _tokenURI)
public
onlyRole(CONTRACT_ROLE)
returns (uint256)
isStaked()
{
//Continue coding...
}
}

How to send ETH directly from ERC721 (OpenZeppelin) contract to the PaymentSplitter contract?

I have an openZeppelin ERC721 NFT contract (MyNFTPrice.sol) and also a separate PaymentSplitter contract. My understanding is that these two contract need to be deployed separately. My question is, how do I send the price of minting from my NFT contract (MyNFTPrice.sol) to the PaymentSplitter contract? Currently, the price for minting an NFT resides in the MyNFTPrice.sol contract address.
MyNFTPrice.sol
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract MyNFTPrice is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() public ERC721("MyNFTPrice", "NFTPRICE") {}
// Mint new NFT
function mintNFT(address recipient, string memory tokenURI) public payable {
require(msg.value >= 50000000000000000, "You need 0.05 ETH to mint the NFT");
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);
}
}
You can use the transfer() member of the address payable.
function mintNFT(address recipient, string memory tokenURI) public payable {
require(msg.value >= 50000000000000000, "You need 0.05 ETH to mint the NFT");
// effectively redirects the `msg.value` to the `0x123` address
payable(address(0x123)).transfer(msg.value);
// ... rest of your code
}
Replace the 0x123 to the real address of the PaymentSplitter.
You can also store the address in a variable and change it when you need to. In this case, it's recommended to use an authorization mechanism, such as the Ownable pattern, so that only an authorized sender can change the value.
Since the PaymentSplitter is a contract, it needs to contain the receive() or fallback() payable function. Otherwise the PaymentSplitter as the receiver would reject the incoming payment and effectively cause the whole mintNFT() transaction to revert.
contract PaymentSplitter {
receive() external payable {
// can be empty
}
}

Remove unstrusted token from ERC20 Smart Contract

I have a question and I try to google without much existence.
Let's take the example of this token:
1inch Token
So you can see that it has different tokens that people have sent to that address.
If I were the owner, how could I implement a function to withdraw all those tokens to my wallet?
Your contract can define the ERC20 interface function transfer(), and then execute this function on the external token contract.
pragma solidity ^0.8;
interface IERC20 {
function transfer(address _to, uint256 _amount) external returns (bool);
}
contract MyContract {
modifier onlyOwner {
require(msg.sender == address(0x123), 'Not authorized');
_;
}
function withdrawERC20Token(address _tokenContractAddress, uint256 _amount) external onlyOwner {
IERC20 token = IERC20(_tokenContractAddress);
// transfer the `_amount` of tokens (mind the decimals) from this contract address
// to the `msg.sender` - the caller of the `withdrawERC20Token()` function
bool success = token.transfer(msg.sender, _amount);
require(success, 'Could not withdraw');
}
}