How to get the address of a contract deployed by another contract - ethereum

-----START EDIT-----
I don't know what I was doing wrong before, but the code below was somehow not working for me, and now is working, and it's exactly the same. I don't know how or what I was missing before, but both this minimal example and the real project I am working on is working now. Obviously I changed something, but I can't figure out what. I just know it's working now. Sorry for the confusion and thanks to everyone for helping.
-----END EDIT-----
I am new to Solidity and am using the Factory pattern for deploying a contract from another contract. I am trying to get the contract address of the deployed contract, but I am running into errors.
I already tried the solution in this question, but I'm getting the following error: Return argument type struct StorageFactory.ContractData storage ref is not implicitly convertible to expected type (type of first return variable) address.
Here is my code:
// START EDIT (adding version)
pragma solidity ^0.8.0;
// END EDIT
contract StorageFactory {
struct ContractData {
address contractAddress; // I want to save the deployed contract address in a mapping that includes this struct
bool exists;
}
// mapping from address of user who deployed new Storage contract => ContractData struct (which includes the contract address)
mapping(address => ContractData) public userAddressToStruct;
function createStorageContract(address _userAddress) public {
// require that the user has not previously deployed a storage contract
require(!userAddressToStruct[_userAddress].exists, "Account already exists");
// TRYING TO GET THE ADDRESS OF THE NEWLY CREATED CONTRACT HERE, BUT GETTING AN ERROR
address contractAddress = address(new StorageContract(_userAddress));
// trying to save the contractAddress here but unable to isolate the contract address
userAddressToStruct[_userAddress].contractAddress = contractAddress;
userAddressToStruct[_userAddress].exists = true;
}
}
// arbitrary StorageContract being deployed
contract StorageContract {
address immutable deployedBy;
constructor(address _deployedBy) {
deployedBy = _deployedBy;
}
}
How can I get this contract address, so I can store it in the ContractData struct? Thanks.

I compiled your contract, deployed it on Remix, and interacted without issue with this setting
pragma solidity >=0.7.0 <0.9.0;
I think you had this in your contract before
userAddressToStruct[_userAddress] = contractAddress;
instead of this
userAddressToStruct[_userAddress].contractAddress = contractAddress;

You can use the following code to get the address of the deployed contract:
address contractAddress;
(contractAddress,) = new StorageContract(_userAddress);
userAddressToStruct[_userAddress].contractAddress = contractAddress;

Related

Automatically pointing contract address to solidity interface

I'm trying to use a interface on remix IDE and my only issue is that I have to copy and paste the contract's address.
Is there a way that I can point it automatically?
ty.
In Remix IDE, you need to copy and paste the newly deployed address manually.
With frameworks, such as Hardhat, you can retrieve the address of the deployed contract in the code and then pass it to the other contract.
In the example below, we're passing the address of First instance to Second's constructor, using the Hardhat JS framework.
const firstFactory = await ethers.getContractFactory("First");
const first = await firstFactory.deploy();
await first.deployed();
const secondFactory = await ethers.getContractFactory("Second");
const second = await secondFactory.deploy(first.address);
await second.deployed();
pragma solidity ^0.8;
contract First {}
contract Second {
constructor(address firstAddress) {}
}

Error of Big number while using constructer in solidity

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
struct account{
string _name;
uint _acc_id;
uint balance;
}
contract My_acc{
account public person;
constructor(string memory name, uint acc_id, uint _balance){
person._name = name;
person._acc_id = acc_id;
person.balance = _balance;
}
}
I am trying to pass values to struct variable through constructor But I am getting this following error.
creation of My_acc errored: Error encoding arguments: Error: invalid BigNumber string (argument="value", value="", code=INVALID_ARGUMENT, version=bignumber/5.5.0)
I tried running the same code and it worked just fine.
Constructor runs only once and that is at the time of deployment. Since you are passing the values to constructor, you should pass the values at the time of deployment.
My reputation does not seem to allow me to upload the image. Please go through the link below.
https://i.stack.imgur.com/AFBWd.png
So guys, I resolved the error. It wasn't actually an error. It was just a silly mistake that I made as a beginner.
SOLUTION: -
I wasn't actually passing values to constructor initially. Actually when we add constructor in our contract we basically get a input section with our deploy button automatically (even before actually deploying). which have to be used to pass values before deploying our contract.

Explicit type conversion not allowed from "int_const" to "contract"

I am trying to deploy a contract from another contract following the example from here
At some point the example states:
Instanciating a new Counter for someone will look like this:
function createCounter() public {
require (_counters[msg.sender] == Counter(0));
_counters[msg.sender] = new Counter(msg.sender);
}
We first check if the person already owns a counter. If he does not own a counter we instantiate a new counter by passing his address to the Counter constructor and assign the newly created instance to the mapping.
However, when I try that in my factory contract:
pragma solidity >=0.7.0 <0.9.0;
contract Factory {
mapping(address => Campaign) _campaigns;
function createCampaign(uint minContrib) public {
require(_campaigns[msg.sender] == Campaign(0));
_campaigns[msg.sender] = new Campaign(minContrib, msg.sender);
}
}
...
contract Campaign {
/* Irrelevant code skipped ... */
constructor (uint minContrib, address creator) {
manager = creator;
minContribution = minContrib;
}
compilation error pops:
from solidity:
TypeError: Explicit type conversion not allowed from "int_const 0" to "contract Campaign".
--> contracts/3_Ballot.sol:10:43:
|
10 | require(_campaigns[msg.sender] == Campaign(0));
| ^^^^^^^^^^^
What comparison is being made here exactly?
require (_counters[msg.sender] == Counter(0));
What is Counter(0)? An instance of contract (like new Counter(0)) or a type conversion of parameter 'int_const' to 'contract'?
Found this this answer which made things a bit clearer.
Apparently this is trying to compare the Contract deployed at address 0 with thatever is stored at _counters[msg.sender] (which I believe should be the address of a deployed contract).
require (_counters[msg.sender] == Counter(0));
With that in mind, I get the error is saying "we're expecting a Counter or address of contract and you give us an int".
I fixed it with Counter(address(0)).

Best plan of attack for digital certificates for proof of completion on EVM

I am looking to explore the option of creating a digital certificate (as in proof) when someone has completed a portion of training, and for this to be issued on an EVM-compatible blockchain using Solidity.
I have prototyped using ERC721 NFTs to encode a "certificate" however, I'd like to prevent recipients from being able to transfer these certificates. To prevent transfer, I attempted to use the Pause.sol functionality from OpenZeppelin, however, this would result in the entire contract being paused, as opposed to a specific tokenId.
Does anyone have any recommendation on an approach? Am I overcomplicating it if I don't want recipients to be able to trade the certificates (i.e. for them to remain static)? Any pointers would be much appreciated!
The simplest and most raw solution is to just set a mapping value.
pragma solidity ^0.8;
contract TrainingResults {
enum Stage {
NONE,
STAGE_1,
STAGE_2,
COMPLETED
}
mapping (address => Stage) public participantStage;
function setParticipantStage(address _graduate, Stage _stage) external {
require(msg.sender == address(0x123), "Not authorized");
participantStage[_graduate] = _stage;
}
}
Or if you want them to be able to see some kind of NFT in their wallet (that supports NFTs), you can modify the ERC-721 contract to disallow transfers.
For example the OpenZeppelin implementation uses a function named _beforeTokenTransfer() (GitHub link) that can be overwritten to disallow transfers altogether.
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
contract TrainingResults is ERC721 {
constructor() ERC721("TrainingResults", "TR") {}
function _beforeTokenTransfer(address from,address to, uint256 tokenId) override internal {
// Allow only for the admin
// as this function is called on token mint as well
require(msg.sender == address(0x123), "Cannot transfer tokens");
}
}

How do I solve the Smart Contract error "returned values aren't valid"?

I am trying to read basic information from a smart contract using web3.js (GRAPH Token):
https://etherscan.io/address/0xc944e90c64b2c07662a292be6244bdf05cda44a7#code
This is my super simple react web3.js setup:
import Web3 from 'web3';
...
useEffect(() => {
const start = async () => {
const web3 = new Web3('https://bsc-dataseed1.binance.org:443')
const abi = [{"inputs":[{"internalType":"uint256","name":"_initialSupply","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MinterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"NewOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"NewPendingOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingGovernor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
const address = '0xc944E90C64B2c07662A292be6244BDf05Cda44a7'
const contract = new web3.eth.Contract(abi, address)
console.log(contract);
const i = await contract.methods.getName().call()
console.log(i); // => ERROR
}
start()
}, [])
And it throws error:
Error: Returned values aren't valid, did it run Out of Gas? You might also see this error if you are not using the correct ABI for the contract you are retrieving data from, requesting data from a block number that does not exist, or querying a node which is not fully synced.
This is a known and misleading error which usually means that the address or the contract abi is invalid but I verified it is correct.
I researched this error for two days but didn't manage to solve this issue... any suggestions?
You're trying to interact with an Ethereum contract, using a BSC (Binance Smart Chain) Web3 provider (in your case https://bsc-dataseed1.binance.org:443). This results in trying to call the getName() function on the BSC address (which doesn't contain any contract).
Ethereum and BSC are different networks, unrelated to each other.
Solution: Use an Ethereum mainnet provider (for example Infura is widely used).