I was looking at the code on the Ethereum website, what does this code do?
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData); }
Available at: https://ethereum.org/token#full-coin-code
Thanks!
It does nothing as it's an interface. An interface is a way to define constraints so that you can communicate with any object that implements this and know that the functions defined in the interface will existing in the implementation.
interface tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData);
}
One example of this would be a way from one contract to communicate to another and looks like an ERC223 implementation for a recipient
In contract you want to communicate to you have to have implemented the tokenRecipient e.g.
pragma solidity ^0.4.0;
interface tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData);
}
contract MyContract is tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) {
// functionality
}
}
So if we now implement a contract me know that we can interact with any contract that has tokenRecipient implemented e.g.
pragma solidity ^0.4.0;
interface tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData);
}
contract RemoteContract {
function func(address _addr, uint _value) {
tokenRecipient _tokenRecipient = tokenRecipient(_addr);
_tokenRecipient.receiveApproval(msg.sender, _value, address(this), empty);
}
}
It will error if the call fails which is what we need to happen to prevent things such as a token being sent to a contract which cannot do anything with it. As Solidity is atom and works in a transactional way if the contract cannot receive it then it will rollback all functionality already executed.
Related
I'm trying to make a dynamic rule builder in solidity, I have a role manager contract that looks like so:
import "#openzeppelin/contracts/access/Ownable.sol";
// The Ownable contract to manage the contract owner
contract RoleManager is Ownable {
mapping(bytes32 => function(bytes32, address, address[] memory, uint256[] memory, bytes[] memory, string memory) external view returns (bool)) public rules;
// Set the rule for the given role
function setRule(bytes32 role, function(bytes32, address, address[] memory, uint256[] memory, bytes[] memory, string memory) external view returns (bool) rule) public onlyOwner {
rules[role] = rule;
}
//...
}
Maybe my understanding of what function parameter is wrong, I would like to build a dynamic function, How to I generate a function on ethers to pass to this ?
Use interface :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/access/Ownable.sol";
interface IRule {
function rule (bytes32 data, address addr,
address[] memory addrArr, uint256[] memory uintArr,
bytes[] memory dataArr, string memory str)
external view returns (bool);
}
contract Demo is Ownable {
mapping(bytes32 => IRule) public rules;
function setRule(bytes32 role, IRule rule) public onlyOwner {
rules[role] = rule;
}
}
I am learning how to write a smart contract for NFT collections and the following is the example function given by the tutorial I read:
function _burn(uint256 tokenId) internal virtual override {
super._burn(tokenId);
if (bytes(_tokenURIs[tokenId]).length != 0) {
delete _tokenURIs[tokenId];
}
}
I recognise that this function will not remove the token from the blockchain entirely. Instead, it will remove the URI of the token (regardless of who owns it). As a result, the token will still in the collection and be displayed on trading platforms, but the metadata will be gone (but it may take time to be in effect as platforms are not refreshing metadata frequently).
I wonder if this is the right practice for burn function. It would be greatly helpful for me if someone can provide me an example of how burn function is achieved on other NFT smart contracts.
Here is the easiest way to add burn function to an NFT.
GO to Openzepplin Wizard
Click ERC721
Give your token a name and symbol.
Click on mintable and burnable, and you would get mintable and burnable NFT token contract.
Here is a sample:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC721, ERC721Burnable, Ownable {
constructor() ERC721("MyToken", "MTK") {}
function safeMint(address to, uint256 tokenId) public onlyOwner {
_safeMint(to, tokenId);
}
}
The corresponding OZ wizard interface would look like this:
You would get the following public burn function:
From Openzepplin ERC721 burnable contract
Update
You can make the contract both enumarable and burnable:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC721, ERC721Enumerable, ERC721Burnable, Ownable {
constructor() ERC721("MyToken", "MTK") {}
function safeMint(address to, uint256 tokenId) public onlyOwner {
_safeMint(to, tokenId);
}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
I'm attempting to write a simple solidity contract that can:
receive ETH
convert ETH to WETH
display ETH balance
display WETH balance
ETH operations appear to work as expected however whenever I try to call any of the WETH functions I receive an error and the transaction is reverted.
Is there something wrong with the way I am trying to instantiate or interact with the WETH token?
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
}
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint) external;
}
contract Scrath {
address private weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
function sendEth() external payable {}
function ethBalance() public view returns(uint256 _balance) {
_balance = address(this).balance;
return _balance;
}
function convertToWeth() external payable {
uint256 eth = ethBalance();
IWETH(weth).deposit{value: eth}();
}
function wethBalance() external view returns(uint256 _balance) {
_balance = IWETH(weth).balanceOf(address(this));
return _balance;
}
}
I can convert ETH to WETH via WETH smart contract and deposit it in my smart contract address, but when I want to convert WETH in my smart contract address to ETH via WETH smart contract and withdraw it to my wallet address, I can't do it.
pragma solidity ^0.5.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint256 value) external payable;
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract testwithdraw {
uint256 public ETHAnt;
address public WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
function deposit() public payable{
ETHAnt = msg.value;
IWETH(WETH).deposit.value(ETHAnt)();
}
function getContractBalance(address _to) public view returns(uint) {
uint256 Balance = IERC20(WETH).balanceOf(_to);
return Balance;
}
function withdraw(uint256 _value) public payable {
IWETH(WETH).withdraw.value(_value);
}
}
When using the withdraw function, it tells me that it ran successfully. But I see that the from in the log is actually my wallet address, and the to is my smart contract address. What's going on here?
status true Transaction mined and execution succeed
transaction hash 0x2859b5188b12cb2f0849a26777a5d2d0972e0e2ce000b548b80f3e5ae3b85b32
from 0xAb2942DEcDEa92A43d84DE7097a2e8df373e41Ab
to testwithdraw.withdraw(uint256) 0xa5f43d3A0C3ee2A99511A14698F0DB082491C751
gas 22323 gas
transaction cost 22323 gas
hash 0x2859b5188b12cb2f0849a26777a5d2d0972e0e2ce000b548b80f3e5ae3b85b32
input 0x2e1...00000
decoded input {
"uint256 _value": "1000000000000000000000"
}
decoded output -
logs []
val 0 wei
When you're withdrawing ETH using IWETH(WETH).withdraw.value(_value), it withdraws ETH from WETH contract and stores them on your contract. In order to be able to withdraw received funds, you need to add something like
payable(msg.sender).transfer(address(this).balance) in your withdraw function.
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
And along with this error i am recieving this error message
This contract may be abstract, not implement an abstract parent's methods completely or not invoke an inherited contract's constructor correctly.
what can i do to work around this?
You are trying to deploy an interface, which is not possible because it doesn't contain any code - just definition of functions.
If you already have a contract that implements this interface, you need to select it in the "Deploy" tab, see the screnshot:
If you haven't implemented the contract, you're in the very beginning and need to implement the whole thing to have a working ERC-20 token contract.
There is no "best way" to create an ERC-20 token, because each contract can be implemented differently but still implement the ERC-20 standard. For starters, I'd recommend reading the OpenZeppelin docs and their source codes to see how they implement the standard. Or if you google "minimal erc-20 contract", you'll find few more implementations that might be easier to grasp.
pragma solidity ^0.8;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
contract MyContract is IERC20 {
function totalSupply() external view returns (uint256) {
// TODO implement this function
}
function balanceOf(address who) external view returns (uint256) {
// TODO implement this function
}
// TODO implement all functions of the interface
}