Clone Factory in Upgradeable smart contract(UUPS proxy) - ethereum

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

Related

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

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.

How to override _setupDecimals() function in OpenZeppelin

How can override Opezeppelin default decimal point of 18. The documentation says the _setupDecimals() should be called from a constructor; what am I doing wrong.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
uint8 _decimals;
constructor() ERC20("MyToken", "MTK") {
_decimals = 3;
function _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
_mint(msg.sender, 5000 * 10 ** decimals());
}
}
_setupDecimals() was available in the OpenZeppelin version 3 (docs, GitHub).
Your import statement imports the latest version of the OpenZeppelin library, which is currently v4. This one implements the decimals() function (docs, GitHub) that you can override.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor() ERC20("MyToken", "MTK") {
_mint(msg.sender, 5000 * 10 ** decimals());
}
function decimals() override public view returns (uint8) {
return 8;
}
}

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.

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

Getting the length of public array variable (getter)

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.