ERC20 for Multiple Tokens in a single contract - ethereum

I am trying to make a contract that has two different tokens used for different aspects of the contract. I would like both of the tokens to be able to fit ERC20 standards but I am not sure how to specify unique variables and functions for each.

If you consider the structure of an ERC 20 token : https://github.com/ConsenSys/Tokens/blob/master/Token_Contracts/contracts/Token.sol , you will see that what you are proposing, although possible, would be a little messy. But more importantly it would transform your token contract into a non-ERC20 token.
uint256 public totalSupply; would need to be replaced with either a mapping or a two separate parameters.
The same would be for managing balances, you would need to change the signature of each method to take an additional parameter for specifying the token you want or create specific method for each token within the contract:
function balanceOf(address _owner) constant returns (uint256 balance);
Would need to be either:
function balanceOf(address _owner, uint256 token_id) constant returns (uint256 balance);
or
function balanceOfTokenA(address _owner) constant returns (uint256 balance);
function balanceOfTokenB(address _owner) constant returns (uint256 balance);
But like I said, either implementation would make your token contract a non-ERC20 token.
You would be better off having two contracts, then both would be ERC20 compatible. You could then write a third contract for managing them if your requirements are that they need to be interfaced via a single contract.

These days, ERC1155, a "multi-token" standard, seems like a good choice for contracts needing multiple tokens:
https://github.com/ethereum/EIPs/issues/1155
Simple Summary:
A standard interface for contracts that manage multiple token types. A
single deployed contract may include any combination of fungible
tokens, non-fungible tokens or other configurations (e.g.
semi-fungible tokens).
See also the openzeppelin implementation

Related

Get error "Derived contract must override function _beforeTokenTransfer"

I want to implement a burn feature in my ERC721 contract in Solidity. To do so, I have imported the function burn from ERC721Burnable.sol.
Since I have imported it I get the following error:
"Derived contract must override function _beforeTokenTransfer".
The same goes with supportsInterface function.
I did override both of them as you can see below. It works but I would like to understand why do I have to do that?
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
I checked Openzeppelin repo, _beforeTokenTransfer is called inside _burn function. At first, I thought it was the main reason but the fact is that _beforeTokenTransfer is also called inside mint and I did not have that error before.
I have no idea why I have to override supportsInterface.
Thanks
ERC721Burnable inherits from two contracts:
abstract contract ERC721Burnable is Context, ERC721 {}
ERC721.sol contract has _beforeTokenTransfer and _afterTokenTransfer unimplemeted functions. you have to implement those in your contract.
from this github issue
ERC721Enumerable and ERC721Burnable both override the
_beforeTokenTransfer and supportsInterface functions. Solidity requires you to "fix" that overriding conflict. If we were able to
address that in our contract we would, but its a solidity requirement
that the child contract explicitly resolves this.
Looks like you 2 of contracts are conflicting inhering supportsInterface

Difference between IERC20 and just address

There are two ways of declaration ERC20 in other contracts:
IERC20 public token, and then connecting to it like token.transfer;
address public token, and then connecting to it like IERC20(token).transfer.
Is there any difference between these two ways of declaration? If so, what is more preferred for usage?
The only difference is during compilation, when the compiler would give you an error if you tried to use one type where the other is required.
In terms of runtime, they are both (160-bit) ethereum addresses.
In your example, it makes more sense to use the type IERC20, because that is the intended type of the variable token.

Are Interfaces used for the sole purpose of generating ABI's in Solidity?

I have been following Solidity, Blockchain, and Smart Contract Course – Beginner to Expert Python Tutorial (https://www.youtube.com/watch?v=M576WGiDBdQ&t=28658s).
At a certain point in the tutorial (around hour 9), the following line of code exists:
weth=interface.IWeth(SomeAddress)
tx=weth.deposit({"from":account, "value": 0.01*10**18})
My understanding is that interfaces get compiled into ABI for use by some external entity.
the IWeth interface is as follows:
pragma solidity ^0.4.19;
/*this is the interface for the WETH contract */
interface IWeth {
function allowance(address owner, address spender)
external
view
returns (uint256 remaining);
function approve(address spender, uint256 value)
external
returns (bool success);
function balanceOf(address owner) external view returns (uint256 balance);
function decimals() external view returns (uint8 decimalPlaces);
function name() external view returns (string memory tokenName);
function symbol() external view returns (string memory tokenSymbol);
function totalSupply() external view returns (uint256 totalTokensIssued);
function transfer(address to, uint256 value)
external
returns (bool success);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool success);
function deposit() external;
function withdraw(uint256 wad) external;
}
The above interface is not implemented anywhere in the project but the project compiles and runs just fine. In my limited understanding of OOP, shouldn't an interface be implemented somewhere? if so, where is it implemented? If not, does the interface ( in this case IWeth) exist for the sole purpose of generating an ABI?
Also, I'm confused about how the interface is used as in weth=interface.IWeth(SomeAddress). In general, how can we write ...InterfaceName(someArg) when it is not even declared in the interface file?
Thanks in advance!
You can use an interface in your contract to call functions in another contract. Interfaces are most useful when you need to add functionality but instead of adding complexity to your application you use it from another contract. They reduce code duplication.
brownie is already loading interfaces. This is from docs
The InterfaceContainer object (available as interface) provides access
to the interfaces within your project’s interfaces/ folder.
interface.IWeth(SomeAddress) this tells Ethereum virtual machine to create a contract instance of given contract address with the functionalities of the interface. And then your app is calling deposit of that contract instance

Solidity - Add Total Supply

I'm learning solidity on remix
I'm also referencing this open source api for token creation.
Right here they provide a _totalSupply() function that I'd like to wire to my smart contract so it shows the total amount of tokens why I deploy it.
What am doing wrong here?
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
contract Foobar is ERC20 {
constructor(uint256 initialSupply) public ERC20("Foobar", "FOO") {
_mint(msg.sender, initialSupply);
// add totalSupply here
_totalSupply(uint256 5000000000000000000000000000000000000000);
}
}
OpenZeppelin ERC20 _totalSupply is a private property, which means you can't access it from a derived contract (in your case Foobar).
GitHub link to the property definition
Solidity docs on visibility modifiers
Also your syntax is incorrect. If the property were at least internal, you could set its value as
_totalSupply = 5000000000000000000000000000000000000000;
or in a more readable way
_totalSupply = 5 * 1e39;
If you want to change its visibility, you'll need to copy the (parent) ERC20 contract to your IDE and change the import statement to reflect the new (local) location. Then you'll be able to update the property visibility in your local copy of the contract.
Mind that the OpenZeppelin ERC20 contains relative import paths (e.g. import "./IERC20.sol";). You'll need to rewrite these in your local copy as well, so that they point back to the GitHub locations. Otherwise, the compiler would be trying to import non-existing local files.
OpenZeppelin contracts automatically update totalSupply when you mint or burn tokens. They also automatically expose this as a variable you can read. You do not need, and you should not and you cannot set totalSupply by hand, because then the number of distributed tokens would not match the total supply.

IERC20 public declaration with another address?

I am new to solidity, but checking through a specific contract I found the following line of code in the IERC20 declaration:
IERC20 public "TOKEN NAME" = IERC20("THE ADDRESS OF ANOTHER CONTRACT");
This code was found in a contract that is effectively a fork of another project, but the developers say they are unrelated. Of course, people are just FOMO into the token - I know this forum here is not for this type of discussion so I'll abstain from the same.
However, from a solidity coding perspective, why would one write this line of code directly referencing another contract address (the forked address) when making the IERC20 declaration - what does this do, is there a purpose to this?
It seems to me that this is easier and more reliable. Alternatively, you can pass this address in constructor parameters, or provide a special method to set it.
The IERC20 is an interface that defines expected functions arguments and return values.
It helps validating whether the caller is passing correct data types, amount of arguments, and helps parsing the returned data to expected types.
Let's show it on a very simple interface
interface IGame {
function play(uint256 randomNumber) returns (bool won);
}
Elsewhere in your contract, you define a variable that uses this interface
IGame game = Game("0xthe_game_address");
You can then directly call the other contract's methods defined in the interface and pass the return values to your variables.
bool didIWin = game.play(1);
The call would fail if the game contract didn't have the play method or didn't return any value (plus in few other cases).
As for why is the address hardcoded, it's probably just to simplify the development as Mad Jackal already said in their answer.
One more plausible reason in some cases is to gain more trust by showing users that the contract admins are not able to cheat you by changing the destination address (possibly to a contract made by them doing whatever they want).
Edit: If the another contract's address is really unrelated and useless (meaning, the fork is not calling it), it's probably just a human error and the developer forgot to remove it.