I have simple smart contract in Solidity. I want to call the function getHello() after I deployed the smart contract (to see variable in deployed contract without calling it by myself). Can I do this?
pragma solidity 0.5.12;
contract Hello {
string public helloStr = "Hello, world 2!";
uint[] public nums = [10, 20, 30];
function getHello() public view returns (string memory) {
return helloStr;
}
function pushNewElement(uint newElement) public returns (uint) {
nums.push(newElement);
}
function popLastElement () public returns (uint) {
nums.pop();
}
function setHello(string memory newHello) public {
helloStr = newHello;
}
}
For getting public variable the compiler automatically formed function.
In you case you can get hello string with function with hash c660ab0e
Or use your function getHello().
For calling function(example, helloStr()) you should use:
{"jsonrpc":"2.0","method":"eth_call", "params":[{"to":"address your smart contract", "data":"0xc660ab0e"}, "latest"],"id":1}
Or use web3 with call:
https://web3js.readthedocs.io/en/v1.2.0/web3-eth.html#call
Yes, you will see "hello world 2" after deployed the contract but you will never be able to see "newHello" output. because it sets the empty string whenever you setHello() function is using.
Related
so, First, I imported the simpleStorage contract and then wrote this function createNeewContracts() to push the contract address into an array
everything was going smooth and I got an idea
"why not just use a struct of two variables 1. string (name of the contract owner) and 2. address (of the contract the owner owns) and i can then have name of owner and his contract as a struct stored in an array named contractAndThereArray"
I could have used mapping but I used struct and array to do the work
I ran into a problem it say
"TypeError: Invalid type for argument in function call. Invalid implicit conversion from contract SimpleStorage1 to address requested."
here is the code:-
contract StorageFactory{
// SimpleStorage public simpleStorage;
struct ownerAndThereContracts {
string name;
address nf;
}
ownerAndThereContracts[] public saveYourContracts;
SimpleStorage1[] public x;
// mapping(string => address) y;
uint256 counter;
function createNewContracts() public {
SimpleStorage1 simpleStorage = new SimpleStorage1();
x.push(simpleStorage);
// address j = simpleStorage;
}
function refering(string memory _name) public {
counter++;
SimpleStorage1 simpleStorage2 = SimpleStorage1(x[counter]);
saveYourContracts.push(ownerAndThereContracts(_name,simpleStorage2)); // the error occurs here it says simpleStorage2 is not address but contract
}
}
The problem is with the function referring where i tried to refer the address of a contract with the owners name but seems there is a problem
Please,if someone can explain it. Please explain I need your help guys
i've been tried to solve it for hours now but nothing seems to fit
I tried to get into your logic and fixed your contract and solve your mistake. Specifically, your error states that you cannot insert an instance of a contract into a field with datatype address. In order to solve this problem you need to cast the contract instance in address datatype. You can see the contract in the following lines, I have also inserted some notes to let you understand what I have changed:
// SDPX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "./SimpleStorage1.sol";
contract StorageFactory{
uint256 counter;
struct ownerAndThereContracts{
string name;
address nf; // NOTE: I assume that it's the SimpleStorage address
}
ownerAndThereContracts[] public saveYourContracts;
SimpleStorage1[] public x;
function createNewContracts() public {
SimpleStorage1 simpleStorage = new SimpleStorage1();
x.push(simpleStorage);
}
function refering(string memory _name) public {
// NOTE: I assume that when creating new contract, then you must refering it directly to an owner.
// In this case, I retrieve the length of array in details the last element index.
counter = x.length-1;
SimpleStorage1 simpleStorage2 = SimpleStorage1(x[counter]);
// NOTE: You must cast your contract instance to an address for put it into your struct (because the datatype is 'address')
saveYourContracts.push(ownerAndThereContracts(_name,address(simpleStorage2)));
}
}
Ok first i fixed your code, you are missing 2 casting, first to address and then to a paybale address.
Here:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.15;
contract SimpleStorage1{
}
contract StorageFactory{
// SimpleStorage public simpleStorage;
struct ownerAndThereContracts {
string name;
address nf;
}
ownerAndThereContracts[] public saveYourContracts;
SimpleStorage1[] public x;
// mapping(string => address) y;
uint256 counter;
function createNewContracts() public {
SimpleStorage1 simpleStorage = new SimpleStorage1();
x.push(simpleStorage);
// address j = simpleStorage;
}
function refering(string memory _name) public {
counter++;
SimpleStorage1 simpleStorage2 = SimpleStorage1(x[counter]);
address simpleStorage2Address = address(simpleStorage2); //first cast to address
address payable _finalCast = payable(simpleStorage2Address); // then cast to payable address
saveYourContracts.push(ownerAndThereContracts(_name, _finalCast));
}
But you should know that this is a very costy contract, you should take out all the process of saving the contract to a environment like c or java and only create the contract through solidity so the objects on memory wont cost you.
Anyway good luck!
From docs: contract-types
Explicit conversion to and from the address payable type is only
possible if the contract type has a receive or payable fallback
function. The conversion is still performed using address(x). If the
contract type does not have a receive or payable fallback function,
the conversion to address payable can be done using
payable(address(x))
I explained here contract-type vs address type
In Solidity a contract variable is really just an address under the
hood.
I got stucked in thoughts guys and I need bit of clarification to move it forward.
(Description is about real problem, code is for best (I hope so..) understanding me)
I have main contract A that uses erc20 token and its transfer functions, there is also inherited Ownable and whitelist with accessing addresses of contracts e.g. B,
I passing A address to the B constructor
I created instance of A in B (because in B I calculate collateral and I want to split to two different contracts)
Protecting A using Ownable it's enough from accessing A from 3rd party while interacting with A from A, Ownable in B isnt work because can't use right msg.sender, without modifiers someone can create instance of B in his contract and have access to my A, isn't it?
Thanks in advance
EDIT: I change a code for more to understand
// SPDX-License-Identifier: MIT
pragma solidity 0.8;
contract Ownable {
mapping (address => bool) private whiteListed;
modifier onlyWhiteListed {
require(whiteListed[msg.sender] == true, "You're not whitelisted");
_;
}
constructor () {
whiteListed[msg.sender] = true;
}
function setWhiteListed(address addr, bool trueOrFalse) public onlyWhiteListed {
whiteListed[addr] = trueOrFalse;
}
function getWhiteListed(address addr) public view returns (bool) {
return whiteListed[addr];
}
}
contract A is Ownable {
B public b;
event LogMsgSender(address who);
constructor() {
b = new B(address(this));
//setWhiteListed(address(this),true);
setWhiteListed(address(b),true);
}
function callMe() public onlyWhiteListed { // here I can only get real caller msg.sender
emit LogMsgSender(msg.sender); // when interact with that contract, not outside of contract
}
function callSender(address sender) public onlyWhiteListed { // here I can get real caller msg.sender from other contract
emit LogMsgSender(sender); // but is it worth to passing addresses ?
} // and HERE is my question: is this aproach secure??
}
contract B is Ownable {
A public a;
constructor(address addr) { //in remix I can't deploy in one time while
a = A(addr); //deploying A, I have to deploy copying addresses of A and do it separately
} //and after deploying also setWhiteListed() to whiteList in A
function callMe() public onlyWhiteListed { // this call isn't good for interact with sender, it's exlusive for calling as contract B
a.callMe(); // copies of this contract can
}
function callSender() public onlyWhiteListed { // modifiers protect from 3rd party contracts but
a.callSender(msg.sender); // that way it only can be used by deployer and whitelisted, (without modifiers they aren't secure)
} // bad idea ofc is adding to whitelist all over and over and
// it's impossible to recognize which to add which not
}
contract C {
B public b;
constructor(address addr) {
b = B(addr);
}
function callMe() public { //when modifiers is added this contract can't call these functions
b.callMe(); // but with modifiers functions can't be used to get right sender address
}
function callSender() public {
b.callSender();
}
}
So now I'm deciding to inherite e.g. B is A and I simply get right sender, what do you think?
You've got a lot of syntax/logic errors in the code you posted. Not only are you missing onlyOwner modifiers, but your calls in B are via the type A: A.receiveToken() is not the same as a.receiveToken() ... so you've probably made several typos in posting your question (Should say a=A(aAddr); in the constructor etc).
The msg.sender will be "b" when b calls a.sendToken() but tx.origin will be unchanged. Checking msg.sender checks which contract called you. In other words, it is checking (inside onlyOwner of A.sendToken) whether b is the one that called a.sendToken().
Start by fixing all the errors and then insert some debug logging for yourself, so you can see how msg.sender is changing during the calls. You can also log tx.origin to see how that remains the original sender.
The point is that the owner of the A that B created is that particular instance of B (b). It's therefore "natural" that inside B, it can call a.whatever() as a's owner.
You didn't specify, but if you are using the Ownable contract from openzeppelin you need to pass the modifier onlyOwner for the methods that you want to be protected. Ex:
function sendToken(uint value) public onlyOwner {
//transferFrom
emit Sent(value);
}
I am implementing a factory pattern contract and on my constructor I want to trigger a function which deposits into the contract
--Factory--
function newChild() {
Child child = new Child(potentialPayoutAmount);
children[_childId] = address(child);
}
function getChild()view public returns (address) {
return children[_campaignId];
}
--Child Contract--
address payable public spender;
constructor(uint256 _potentialPayoutAmount) {
autoDeposit(_potentialPayoutAmount)
}
function autoDeposit(uint256 _potentialPayoutAmount) {
depositedFor[receiver] = depositedFor[receiver] + _potentialPayoutamount;
}
So my problem is that I want the spender address in the child contract to be the account that is spending the money, even though the autoDeposit function is obviously being triggered from the factory contract.
Any suggestions would help. Happy to elaborate if I was unclear.
Thanks!
I want to create a smart contract (called Deal) which, after it gets deployed, It calls another smart contract (called AddressBook) to register his address on the global AddressBook smart contract. The code I am using works, but unfortunately my newly deployed smart contract is not using the address from the AddressBook smart contract, but instead it uses his own address to call the addAddress function. The red marking shows the output if I am calling addressbook.getAddresses(addresses) inside the Deal contract. The blue marking shows the output if I am calling the getAddresses function within the AddressBook contract. So what I want is the blue output within the Deal contract
Image of the Output
Can anybody tell me how I can add the addesses of my deployed contract to a global AddressBook contract?
This his how my AddressBook smart contract looks like. I would like to add all deployed smart contracts at this contact.
contract AddressBook {
mapping(address => address[]) private _addresses;
mapping(address => mapping(address => string)) private _aliases;
function getAddresses() public view returns (address[]) {
return _addresses[msg.sender];
}
function addAddress(address addr, string _alias) public payable {
_addresses[msg.sender].push(addr);
_aliases[msg.sender][addr] = _alias;
}
function removeAddress(address addr) public payable {
uint length = _addresses[msg.sender].length;
for(uint i = 0; i < length; i++) {
if (addr == _addresses[msg.sender][i]) {
if (1 < _addresses[msg.sender].length && i < length-1) {
_addresses[msg.sender][i] = _addresses[msg.sender][length-1];
}
delete _addresses[msg.sender][length-1];
_addresses[msg.sender].length--;
delete _aliases[msg.sender][addr];
break;
}
}
}
function getAlias(address addr) public view returns (string) {
return _aliases[msg.sender][addr];
}
}
This is the smart contract I want to deploy and register at the global
AddressBook smart contract:
contract Deal {
AddressBook addressBook;
address public owner;
address public buyerAddr;
address private addr;
string private metaData;
uint private duration;
uint private price;
string private typeOfData;
string private gateKeeper;
event SafepaySent(address buyer, uint value, uint now);
/// The smart contract's constructor
function Deal(address _addressBook) public payable {
/// The seller is the contract's owner
owner = msg.sender;
AddressBook a = AddressBook(_addressBook);
a.addAddress(owner,"test");
}
}
function getAddresses(address _addressBook) public view returns (address[]) {
return AddressBook(_addressBook).getAddresses();
}
}
contract AddressBook {
function getAddresses() public view returns (address[]);
function addAddress(address addr, string _alias) public payable ;
function removeAddress(address addr) public payable;
function getAlias(address addr) public view returns (string);
}
Now I want to call the AddressBook.getAddresses() function within the AddressBook smart contract and I want to receive the addresses of all deployed Deal contracts. However, I am not receiving any address within the AddressBook smart contract. If I am calling the function Deal.getAddresses("address of the global Addressbook") I get the address of the newly deployed smart contract. But this is not what I want.
First if you want to use AddressBook as a global smart contract to track and load all the Deal contracts. You should already deploy the AddressBook contract and save it's address. Then you can load the AddressBook contract inside the constructor of the Deal contract and add the address of current Deal contract which is going to deploy, inside the already deployed global AddressBook contract. I did some working on the given contracts. I am using an array of addresses inside the AddressBook contract to track the address of all the Deal contracts. The following example code can give you good idea.
//Address Book Contract
pragma solidity ^0.5.1;
contract AddressBook {
//mapping(address => address[]) private _addresses;
address[] private _addresses;
mapping(address => mapping(address => string)) private _aliases;
function getAddresses() public view returns (address [] memory) {
return _addresses;
}
function addAddress(address addr, string memory _alias) public payable {
_addresses.push(addr);
_aliases[msg.sender][addr] = _alias;
}
}
I just focused on _address here. Following is the deal contract:
pragma solidity ^0.5.1;
import "./AddressBook.sol";
contract Deal {
AddressBook addressBook;
address public owner;
address public buyerAddr;
address private addr;
string private metaData;
uint private duration;
uint private price;
string private typeOfData;
string private gateKeeper;
event SafepaySent(address buyer, uint value, uint now);
/// The smart contract's constructor
constructor(address _addressBook) public payable {
/// The seller is the contract's owner
owner = msg.sender;
addressBook = AddressBook(_addressBook);
addressBook.addAddress(address(this),"test");
}
function getAddresses() public view returns (address[] memory) {
return addressBook.getAddresses();
}
}
You can also test and run this in remix. Hope it works.
I'm using solidity version 0.5.2
pragma solidity ^0.5.2;
contract CampaignFactory{
address[] public deployedCampaigns;
function createCampaign(uint minimum) public{
address newCampaign = new Campaign(minimum,msg.sender); //Error
//here!!!
deployedCampaigns.push(newCampaign);
}
function getDeployedCampaigns() public view returns(address[] memory){
return deployedCampaigns;
}
}
I'm getting the error while assigning calling the Campaign contract inside CampaignFactory contract
TypeError: Type contract Campaign is not implicitly convertible to expected
type address.
address newCampaign = new Campaign(minimum,msg.sender);
I have another contract called Campaign which i want to access inside CampaignFactory.
contract Campaign{
//some variable declarations and some codes here......
and I have the constructor as below
constructor (uint minimum,address creator) public{
manager=creator;
minimumContribution=minimum;
}
You can just cast it:
address newCampaign = address(new Campaign(minimum,msg.sender));
Or better yet, stop using address and use the more specific type Campaign:
pragma solidity ^0.5.2;
contract CampaignFactory{
Campaign[] public deployedCampaigns;
function createCampaign(uint minimum) public {
Campaign newCampaign = new Campaign(minimum, msg.sender);
deployedCampaigns.push(newCampaign);
}
function getDeployedCampaigns() public view returns(Campaign[] memory) {
return deployedCampaigns;
}
}
To call an existing contract from another contract ,pass the contract address inside cast
pragma solidity ^0.5.1;
contract D {
uint x;
constructor (uint a) public {
x = a;
}
function getX() public view returns(uint a)
{
return x;
}
}
contract C {
//DAddress : is the exsiting contract instance address after deployment
function getValue(address DAddress) public view returns(uint a){
D d =D(DAddress);
a=d.getX();
}
}