I'm implementing several variations on a base contract and I want the child to be able to inherit one or both of the variations. When I inherit from both, I get "TypeError: Derived contract must override function "foo". Two or more base classes define function with same name and parameter types."
Code is below, straight from Remix, with the two solutions I've come up with. Solution 1 requires re-implementing something like 10 functions in the child contract, each of which just call "super", which is pretty ugly. Solution 2 requires me to provide a contract for each combination of variations, and with 7 variations, that's ugly too. Any better solutions?
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "hardhat/console.sol";
abstract contract A {
function foo () public virtual {
console.log("A");
}
}
abstract contract B is A {
}
abstract contract C is A {
function foo () public virtual override {
console.log("C");
super.foo();
}
}
contract X is B {} // foo() prints A
contract Y is C {} // foo() prints CA
// Solution 1:
contract Z1 is B, C { // why do I have to override foo() again?
function foo () public override (A, C) {
super.foo();
}
}
// Solution 2:
contract Cprime is B { // duplicate C as child of B
function foo () public virtual override {
console.log("C");
super.foo();
}
}
contract Z2 is Cprime {} // this is what I'd like Z to look like
Related
When I'm learning OpenZeppelin, I found its Ownable library has a function transferOwnership, which can give the owner of current contract to an address.
I can understand change owner to an account address of someone, however, it can also change owner to a contract address.
My question is: If I change owner of current contract to another contract address, how can I use the other contract to handle the owner of my original contract? I tried inheritance with super key word, it doesn't work.
The failure code is as follow.
BTW, if it's useful to change owner of current contract to another contract address? Is there any example project to use this case?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "#openzeppelin/contracts/access/Ownable.sol";
contract MyContract is Ownable {
function getCurrentBalance() public view onlyOwner returns (uint) {
return address(this).balance;
}
receive() external payable {}
}
contract ManageOwner is MyContract {
function changeOwner(address newOwner) public {
super.transferOwnership(newOwner);
}
}
I use interface and success. The codes are as follow:
import "#openzeppelin/contracts/access/Ownable.sol";
contract A is Ownable {
receive() external payable {}
function getCurrentBalance() public view onlyOwner returns (uint) {
return address(this).balance;
}
}
interface I {
function getCurrentBalance() external view returns (uint) ;
function transferOwnership(address newOwner) external;
}
contract B is Ownable {
I public itf = I(contract_A_address_);
receive() external payable {}
function getBalanceOfA() public view onlyOwner returns (uint) {
return itf.getCurrentBalance();
}
function changeAOwner(address newOwner) public onlyOwner{
itf.transferOwnership(newOwner);
}
}
First, deploy contract A.
2nd, copy contract A address to contract B.
3rd, deploy B.
4th, call transferOwnership function of contract A with address of contract B as args.
5th, call changeAOwner function of contract B to handle ownership of contract A.
I'm trying to import some contract files from open zeppelin so my solidity smart contracts can inherit their functionality, when trying to write chai tests that run on my smart contracts at compile time I get an error in my chai test.
3 passing (2s)
1 failing
1) Contract: Color
minting
creates a new token:
TypeError: contract.totalSupply is not a function
my contract importing the openzeppelin contracts
pragma solidity 0.8.7;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol"; //import base functionality
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; //import totalsupply()
contract color is ERC721 {
string[] public colors;
mapping(string => bool) _colorExists; //mappings are like json objects where value a is searched and its value is returned
constructor() ERC721("Color", "COLOR") {
}
function mint(string memory _color) public{
colors.push(_color);
uint _id = colors.length -1;
_mint(msg.sender,_id);
_colorExists[_color] = true;
}
}
and lastly my test file ( I have shortened it to show only the test giving me errors)
const { assert } = require('chai')
const Color = artifacts.require('./Color.sol')
require('chai')
.use(require('chai-as-promised'))
.should()
contract('Color', (accounts) =>{
let FormControlStatic
before(async ()=>{
contract =
await Color.deployed()
})
describe('minting', async ()=>{
it('creates a new token', async ()=>{
const result = await contract.mint('#EC058E')
console.log(result)
const totalSupply = await contract.totalSupply()
assert.equal(totalSupply,1)
console.log(result)
})
})
})
also if we look at the file containing the function totalSupply() it is publicly scoped so it should be visible outside the function via import
I did some digging and imported the file that the actual function IS in from openzeppelin however it seems that I still get the same error, I tried compiling separately to see if recompiling after changing would resolve but it didn't
not sure if anyone else has gone through this recently or might have a solution
also I'm importing the current version here
https://www.npmjs.com/package/#openzeppelin/contracts
thanks!
We must extend IERC721Enumerable contracts, and, implements its virtual functions.
contract Color is ERC721, IERC721Enumerable { // We must extends IERC721Enumerable
string[] public colors;
mapping(string => bool) _colorExists;
constructor() ERC721("Color", "COLOR") {}
function mint(string memory _color) public {
colors.push(_color);
uint256 _id = colors.length - 1;
// _mint(msg.sender,_id);
_colorExists[_color] = true;
}
// And must override below three functions
function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) {
// You need update this logic.
// ...
return 3;
}
function totalSupply() external view override returns (uint256) {
// You need update this logic.
// ...
return 1;
}
function tokenByIndex(uint256 index) external view override returns (uint256) {
// You need update this logic.
// ...
return 5;
}
}
Then, we can call totalSupply() method
Below is a complete implementation of the smart contract.
As you mentioned in the question, it uses newer versions than the tutorial:
Solidity (0.8.0)
Open Zeppelin (4.3.2)
pragma solidity ^0.8.0; // Note that this is using a newer version than in
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
contract Color is ERC721, ERC721Enumerable {
string[] public colors;
mapping(string => bool) _colorExists;
constructor() ERC721("Color", "COLOR") public {
}
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);
}
function mint(string memory _color) public {
colors.push(_color);
uint _id = colors.length - 1;
_mint(msg.sender, _id);
_colorExists[_color] = true;
}
}
You can also take a look at OpenZeppelin's section about Extending Contracts to learn about overrides and super.
You can follow these following steps to continue the tutorial.
First create a new contract file with ERC721Enumerable:
./node_modules/.bin/truffle-flattener ./node_modules/#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol > contracts/ERC721Enumerable.sol
Second replace old ERC721 with new ERC721Enumerable:
import "./ERC721Enumerable.sol";
contract Color is ERC721Enumerable {
//
}
Delete old ERC721Full.sol files under the contracts folder.
I need to make a function that will be called each time someone called my contract. And I need to do it without using modifiers because there are many functions in my contract and I use third-party contracts.
How can I do it?
You can inherit third-party contracts and make a new child contract and then modify each function with a modifier you defined in the child contract, that's the only way to do.
Example:
Contract ThirdParty {
address owner;
function f() public {}
}
Contract Child is ThirdParty {
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function f() public onlyOwner {}
}
contract FirstContract {
function createOtherContract() payable returns(address) {
// this function is payable. I want to take this
// value and use it when creating an instance of
// SecondContract
}
}
contract SecondContract {
function SecondContract() payable {
// SecondContract's constructor which is also payable
}
function acceptEther() payable {
// Some function which accepts ether
}
}
FirstContract will be created from the js app when the user clicks a button on the website. then I want to create an instance of the second contract and pass the ether along to the new contract. I cant figure out how to call SecondContract's constructor from the first contract while sending ether.
Edit: I found the solution for this:
pragma solidity ^0.4.0;
contract B {
function B() payable {}
}
contract A {
address child;
function test() {
child = (new B).value(10)(); //construct a new B with 10 wei
}
}
Source: http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html#how-do-i-initialize-a-contract-with-only-a-specific-amount-of-wei
Using your code it would look something like the following:
pragma solidity ^0.4.0;
contract FirstContract {
function createOtherContract() payable returns(address) {
return (new SecondContract).value(msg.value)();
}
}
contract SecondContract {
function SecondContract() payable {
}
function acceptEther() payable {
// Some function which accepts ether
}
}
I am trying to get the length of array from another contact. How?
contract Lottery {
unint[] public bets;
}
contract CheckLottery {
function CheckLottery() {
Lottery.bets.length;
}
}
You have to expose the length you want as a function return value in the source contract.
The calling contract will need the ABI and contract address, which is handled via the state var and constructor below.
pragma solidity ^0.4.8;
contract Lottery {
uint[] public bets;
function getBetCount()
public
constant
returns(uint betCount)
{
return bets.length;
}
}
contract CheckLottery {
Lottery l;
function CheckLottery(address lottery) {
l = Lottery(lottery);
}
function checkLottery()
public
constant
returns(uint count)
{
return l.getBetCount();
}
}
Hope it helps.