How to call the function of another smart contract in Solidity? With an example of OpenZeppelin transferOwnership function - ethereum

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.

Related

Clone Factory in Upgradeable smart contract(UUPS proxy)

When we use the Create clone factory approach the initialize function takes in the address of the deployed address(_recardAddress) whom we want to clone. In the case of upgradeable contract we get two contracts that is the "Proxy" and "implementation". So whoes address do we have to pass in to the initialize function and why?
I tried passing in the implementation contract address and it works but dont know the reason!
# THIS IS THE FACTORY CONTRACT WHICH MAKES THE CLONES
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "./BlockCard.sol";
import "./CloneFactory.sol";
import "#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "#openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract BlockCardFactory is Initializable,CloneFactory,OwnableUpgradeable,UUPSUpgradeable{
address public BlockCardAddress;
address[] public clonedcontracts;
event BlockCardCreated(address newBlockCard);
//initialising
function initialize( address _recardAddress) initializer public{
BlockCardAddress=_recardAddress;
__Ownable_init();
}
//creating clone
function createBlockCard() public {
address clone=createClone(BlockCardAddress);
BlockCard(clone).initialize();
clonedcontracts.push(clone);
emit BlockCardCreated(clone);
}
//adding into the array
function getAddress(uint i) view external returns(address){
return clonedcontracts[i];
}
//interaction with cloned addresses
function interwithClone(address arr)public view returns(string memory){
BlockCard cloned=BlockCard(arr);
return cloned.getname();
}
//UUPS
function _authorizeUpgrade(address newImplementation)internal override onlyOwner{}
}
#THIS IS THE CONTRACT WHICH NEED TO BE REPLICATED
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "#openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract BlockCard is Initializable,UUPSUpgradeable,OwnableUpgradeable {
struct Person{
string name;
string gender;
uint age;
string bloodgroup;
string DOB;
}
Person person;
function initialize() initializer public{
__Ownable_init();
}
function getname() public view returns(string memory){
return person.name;
}
function setName(string calldata _name) public {
person.name=_name;
}
function setGender(string calldata _gender) public {
person.gender=_gender;
}
function setAge(uint _age) public {
person.age=_age;
}
function setBloodgroup(string calldata _bloodgroup) public {
person.bloodgroup=_bloodgroup;
}
function setDOB(string calldata _DOB) public{
person.DOB=_DOB;
}
//UUPS
function _authorizeUpgrade(address newImplementation)internal override onlyOwner{}
}

How to link my IPFS content to ERC721 contract?

I´m trying to make a simple ERC721 NFT minting contract. I created an image and its corresponding metadata and I´ve uploaded them to the ipfs. When does this image and metadata link with the token created in the smart contract?. I was trying to use this code generated with the Openzeppelin contract wizard:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract MyToken is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("MyToken", "MTK") {}
function safeMint(address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
}
}
But I don't see where I can link my nft image and metadata to the contract. I´ve seen that in ERC721 standart by openzeppelin you can set the base URI and tokenURI with the functions tokenURI and _baseURI, but I don't know exactly how to use them. I was planning to create a multiple-item collection (in the ipfs) so I don't know what to use in my case.
Replace ERC721 with ERC721URIStorage
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract MyToken is ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("MyToken", "MTK") {}
function safeMint(string memory tokenURI, address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, tokenURI);
}
}

totalsupply() is not a function openzeppelin contracts

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.

How do I make a function that is called on every contract call? – Solidity

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 {}
}

Can I send eth to a contract through its constructor from another contract.

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
}
}