There is a way to transfer / mint tokens without ERC20 owner approval method? - solidity

I trying to understand how crowdsale work in this way of buying tokens.
The part of send ether to a contract is ok, but the part of token transfer is still dark for me.
I have a ERC20Mintable token, in the latest version of openzeppelin.
My crowdsale contract will have thousands and thousands of buyers. In most tutorials, they teach transfering tokens with transferFrom, but that requires the approval of ERC20 owner correct ? Is what most of tutorials show. I can mint either, probably because only owner can mint tokens.
My question is: there is a method that users can buy tokens without any action of the ERC20 owner?
Thanks!

Owner approval is needed for transferFrom function. Because with this function you are allowing third-party account transfer from your account to someone.
Let's say I want to transfer token from your account to my brother's account. To be able to do this, you have to give permission first and this permission is stored in a mapping. If you allow me to transfer a specific amount from your account, you first add my account into this mapping
// my address is allowed to transfer token to other address
mapping(address=>mapping(address=>uint256)) allowed;
with approve function.
function approve(address _spender, uint256 _value) public override returns (bool success){
// you are calling this. so you are the msg.sender
// first we are checking if you have enough token to be transferred
require(tokenBalances[msg.sender]>=_value,"insufficient token");
// then you register my account with the _value
allowed[msg.sender][_spender]=_value;
// if in the future there is a dispute, we can check those events for verification
emit Approval(msg.sender,_spender,_value);
return true;
}
This where owner approval used. If you want to transfer money from your account to another account, you use the transfer function:
function transfer(address _to, uint256 _value) public override returns (bool success){
require(tokenBalances[msg.sender]>=_value,"you do not have enough tokens");
tokenBalances[msg.sender]-=_value;
tokenBalances[_to]+=_value;
emit Transfer(msg.sender,_to,_value);
return true;
}

I also finding this solution for me but didn't find any proper solution.
however find a solution for now.
create a function that is payable and pass amount(how much buyer buy) and make a keccak hash with (sender , value and amount) and store in a map and send transfer receive eth to _admin address.
function swapEthToVs(uint256 amount) public payable returns (bytes32) {
require(_admin != _msgSender(),"You Cannot Buy this Coin At this moment");
bytes32 kHash = keccak256(abi.encodePacked(msg.value,amount,_msgSender()));
swapHash[_origin()] = kHash;
payable(address(_admin)).transfer(msg.value);
return kHash;
}
then create api that take (sender , amount ,contractOwner) and call another function with contractOwnerSigner
function verifySwapHash(uint256 eth,address to,uint256 amount) public returns (bool) {
require(swapHash[to] == keccak256(abi.encodePacked(eth, amount, to)),"Invalid hash no trace found");
transfer(to, amount);
delete swapHash[to];
return true;
}
I know this is risky but i didn't found any solution. if you found any solution please describe solution.

Related

Can a solidity smart contract execute the approve function in an erc20 contract on behalf of the msg.sender

Setting up a bank contract to perform deposits and withdraws. I was wondering if its possible for the bank contract can execute the approve function in the erc20 contract on behalf of the msg.sender for the tokens they are wanting to deposit.
Below is my attempt for the bank contract to call the erc20 token contracts approve function. However wouldn't the msg.sender be the bank contract address instead of the original msg.sender (second line of the depositToken function.) This sounds silly but is there a way for the contract to send the request passing in the msg.senders address? If not is there an integrated way for the msg.sender to approve the bank contract address and the amount to enable the bank contract to call the transferFrom function and be provided the allowance.
//best guess on what that would look like inside the function depositTokens
msg.sender = customer;
customer.IER20(usdt).approve.address(this), uint _amount;
address public usdt;
mapping(address => uint) public bankBalance;
constructor() public {
usdt = 0x77c24f0Af71257C0ee26e0E0a108F940D1698d53;
}
usdt = 0x77c24f0Af71257C0ee26e0E0a108F940D1698d53;
function depositTokens(uint _amount) public {
IER20(usdt).approve.address(this), uint _amount;
// Trasnfer usdt tokens to contract
IERC20(usdt).transferFrom(msg.sender, address(this), _amount);
// Update the bank balance in map
bankBalance[msg.sender] = bankBalance[msg.sender] + _amount;
}
//approve function in erc20
function approve(address delegate, uint256 numTokens) public override returns (bool) {
allowed[msg.sender][delegate] = numTokens;
emit Approval(msg.sender, delegate, numTokens);
return true;
The answer is no, the approve function takes the msg.sender as the one that gives allowance. You can see the most used OpenZeppelin implementation here.
However I can see what you are trying to do and I want to add that there is a way to automatically ask an EOA (externally owned account) or a user with a wallet to approve some tokens to the contract before sending a transaction.
I don't know if a wallet does it automatically or you have to code it in the UI but I think that is what you are looking for.
And then after the user already approved your bank, you can remove your first line in the deposit function

How to use ERC20 token to transfer eth in solidity?

I'm writing a defi project to transfer between an ERC20 token and eth. I want to develop a function that accept the ERC20 token from an address then send eth to that address.
What I deal with that ERC20 token was to generate the token in the smart contract and send the token to the user. The problem is that, if user A send some ERC20 token to user B, what should I do to allow user B use the token to ask for eth in my smart contract?
Another simple question is that, how to ask the user to use their wallet (e.g. metamask) to transfer ERC20 token to my smart contract?
Using the payable you would be able to transfer the native token (eth) from your contract into any user's wallet:
function transferEth(address payable _to, uint _amount) public {
(bool success, ) = _to.call{value: _amount}("");
require(success, "Failed to send Ether");
}
Notice that this function above is not safe as any one can call the transfer to your contract, please consider to use the modifier to prevent it.
In your case I can think of a function like:
function claimEth() public {
if (balanceOf(msg.sender) > 100) {
balances[msg.sender] = balances[msg.sender[.sub(100);
transferEth(msg.sender, 5);
}
}

Solidity: transferFrom can't reach allowance value

Here are the steps I follow on Remix:
Deploy my ERC20Basic token and my DEX contract.
DEX.buy > Buy ERC20Basic tokens in exchange of ETH (works fine).
ERC20Basic.approve(contractAddress, tokenAmount) (works fine).
ERC20Basic.allowance > Works fine, function returns the amount of the allowance.
The problem comes when I try to sell tokens with this function from my DEX contract:
function sell(uint256 amount) public {
uint256 allowance = token.allowance(msg.sender, address(this));
require(allowance >= amount, "Check the token allowance");
token.transferFrom(msg.sender, address(this), amount);
payable(msg.sender).transfer(amount);
emit Sold(amount);
}
I still get "Check the token allowance".
When I log the allowance I get 0.
When I log msg.sender and address(this), I get the same addresses I used on the Remix interface to get the value of the allowance manually.
It feels like the allowance is reset to 0 when I call the sell function or that the sell function can't reach the value of the allowance. Maybe this is something about memory and storage?
My allowance function inside of ERC20Basic contract is:
function allowance(address owner, address delegate)
public
view
override
returns (uint256)
{
return allowed[owner][delegate];
}
Approval function:
function approve(address delegate, uint256 numTokens)
public
override
returns (bool)
{
allowed[msg.sender][delegate] = numTokens;
emit Approval(msg.sender, delegate, numTokens);
return true;
}
Allowance structure:
mapping(address => mapping(address => uint256)) allowed;
How are you calling the approve function?
In your code you aren't passing the require statement because your approval wasn't successful. If it was your allowance wouldn't be 0.
You are probably calling the approve function from the contract which won't work because then the msg.sender would be address of the contract not your accounts address.
You have to approve the amount manually outside of the contract for it to work.

Transfer ERC721 from owner to buyer

I'm trying to let other addresses execute the buy function, but it throws me the error ERC721: approve caller is not the owner nor approved for all
this is the code
function testbuy() public payable{
require(ownerOf(1) == _owner, "Already bought");
approve(msg.sender, 1);
safeTransferFrom(_owner, msg.sender, 1);
}
How could I make other address buy the NFT from the owner address? I'm having trouble understanding approve and setApproveForAll.. Thanks :)
Based on the error message, I'm assuming that you're using the Openzeppelin implementation of ERC721.
Since your contract derives from the OZ implementation, you can use their internal functions and don't need to go through the approve() and safeTransferFrom() process. If you wanted to go this way, you would need to invoke the approve() function from the _owner address directly - not by the buying user through the testbuy() function, as this was the logical error in your code.
Specifically, you can use the _transfer() function (source):
function testbuy() public payable{
require(ownerOf(1) == _owner, "Already bought");
_transfer(_owner, msg.sender, 1);
}
You can find your error OpenZeppelin ERC721 here:
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
Address which is calling testbuy() function has to be the owner of the token. In other case it cannot give the approval (or the token has to have approval for all), hence the approve function.

How to withdraw all tokens form my bsc contract

I'm really really inexperienced with contracts and need your help. I created a contract with remix and sent some bnb to it. I want to retrieve it but I can't seem to make it happen.
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);
}
}
This is the code that I'm using from another post but I don't understand it. Do I have to change the "_to" "and "_amount" with the numbers or do I just copy the code and compile it?
I'm really sorry but I have no idea what I did so I just want to take the tokens back.
Thanks
Sorry but you can't withdraw your bnb, bnb isn't a token, bnb is like the ether in ethereum, the native chain currency and the contract doesn't have a function to let you withdraw it, the only way is if you send wbnb, in that case you can look the address of the contract of the wbnb and call the function withdraw of the contract you made
As Jhonny said, BNB is not an actual token, and so your implemented logic won't work to withdraw BNB. But just for you to know, you could create a function which only allows withdrawing BNB (which is the native currency). It would be something like this:
function withdraw(uint _amount) external {
payable(msg.sender).transfer(_amount);
}
Hope you find this useful.