This might be a beginner question, but the thing is confusing
I can see from samples like bellow
https://github.com/acloudfan/Blockchain-Course-Basic-Solidity/blob/93ca256bcf8c436c144425291257dcff5c3b269f/test/TestMetacoin.sol#L18
MetaCoin meta = new MetaCoin();
That a contract can be created/instantiated inside another contract, I want to understand what is happening here? does this create a new contract and deploy, therefore having a new address? or does it works or behaves like an ordinary class like in C++ or java, etc?
I dont know what is the context of the meta instance at this point.
Can someone help explain?
Secondly, this might be related,
What does it mean when two contracts are defined in a single Sol file and the second contract instantiated the first one like below?
pragma solidity 0.4.21;
contract Base {
uint public dataA;
bytes32 public dataB;
function setAB(uint a, bytes32 b) public {
dataA = a;
dataB = b;
}
function getA() public view returns(uint) {
return dataA ;
}
function getB() public view returns(bytes32) {
return dataB ;
}
}
contract Extra {
Base base;
function Extra() public {
base = new Base();
}
...
}
Does the contract base deployed and will have its own address?
Related
pragma solidity ^0.8.0;
contract Counter {
uint public number;
string public name;
constructor(string memory input_name, uint input_number){
name = input_name;
number = input_number;
}
function add () public {
number ++;
}
function subtract() public {
number --;
}
function update_name(string memory update) public {
name = update;
}
I wrote a very basic contract here and I'm wondering why I should write a return statement for each of my functions as it is already returns a value.
Could someone explain my error or the point of the return statement here?
Solidity have the "implicit return" feature, so as you noticed, you may skip the "return" statement in some cases. However, it's discourages, since you're not explicit enough and may cause a lot of confusion and issues.
For details please check the following links:
https://medium.com/#pareshmasani/ethereum-smart-contract-implicit-return-can-go-wrong-33b41c93dbba
https://github.com/ethereum/solidity/issues/3134
https://blog.openzeppelin.com/instadapp-audit/
This is my contract code. Here I'm trying to store the coordinates of a particular trip. While storing the information contract executing fine. But When I retrieve the data, It should give the array of coordinates. But it is throwing an error.
reason: 'insufficient data for uint256 type'
contract TripHistory {
struct Trip {
string lat;
string lon;
}
mapping(string => Trip[]) trips;
function getTrip(string _trip_id) public view returns (Trip[]) {
return trips[_trip_id];
}
function storeTrip(string _trip_id, string _lat, string _lon) public {
trips[_trip_id].push(Trip(_lat, _lon));
}
}
What I'm missing here. Is there any other way to achieve what I'm trying here?
P.S: I'm new to solidity.
First of returning structs is not supported in Solidity directly. Instead you need to return every individual element in the struct as below.
Function xyz(uint256 _value) returns(uint256 User.x, uint256 User.y)
public {}
But then there’s an experimental feature that will help you with returning struct. All that you need to do is add the following after your first pragma line
pragma experimental ABIEncoderV2;
then continue with your code. That should work with no changes to your code.
An example of abiencoderv2 returning struct can be found at this link
It is not possible in solidity to return struct array.
As jlo said in this link, after version 0.8.0, it is possible to return a struct. jlo describes how to set and return an element of array of struct. Here I describe how to set, reset, and return a struct type variable.
I tested it and my test environment is:
private Ethereum network
Geth version 1.10.9-stable (for private network)
Slocjs Compiler version 0.8.7
web3js version 1.5.1
Note, you have to first define the struct type outside of any function inside the contract.
A supper intuitive example code is as follows:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract testContract {
struct funcResultType {
uint[] var1;
string[] var2;
string message;
}
funcResultType private funcResult;
function testSetFunc(string memory inputVar) public payable {
funcResult.var1.push(123);
funcResult.var2.push(inputVar);
funcResult.message = "Done!";
}
function testResetFunc() public payable {
delete funcResult; // reset variales
}
function testGetFunc() public view returns (funcResultType memory){
return funcResult;
}
}
The result of the test with Web3js in the console is as follow:
As you can see the whole variables are accessible. I upload its web3js code in Github in this link.
i'm trying to use a contract instance as a variable of another contract, such as the example below.
pragma solidity ^0.4.23;
contract basic {
uint num1 = 10;
function getNum1() public view returns(uint) {
return num1;
}
function setNum1(uint _num) public returns(uint) {
num1 = _num;
}
}
contract parent {
uint public num2;
basic public b;
constructor() public {
b = new basic();
num2 = 20;
}
function getNum1() public constant returns(uint) {
return b.getNum1();
}
}
while when i test the contract in remix and truffle , it worked well.
enter image description here
but util i deployed the contract "parent" on my private network, parent.getNum1() returned '0' instead of '10' as supposed.
further more, i tried other type of constructors such as take an address of 'basic' as a parameter, it didn't work as well.
i also tried some contracts thats takes another contract instance as a variable, they all didn't work well on private network.
does anybody ever meet this problem? help!!!
coming to close the question now !
i deployed my contract on ropsten test network, and the contract worked well.
it seems that my private network didn't support the usage of calling from another contract. anybody interested can have a try to see.
So, from what I understand, it's a good idea to use temporary contracts and redeploy when a change is necessary. Let's assume that I controlled a smart lightbulb with the following code.
pragma solidity 0.4.24;
contract Lightbulb {
enum LightState { off, on }
address public owner;
LightState light;
LightState constant defaultChoice = LightState.off;
uint public cost = 1 ether;
constructor () public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function turnOn() public payable {
require(msg.value == cost);
light = LightState.on;
}
function turnOff() public {
light = LightState.off;
}
function getState() public view returns (LightState) {
return light;
}
}
Should I just redeploy the contract if I wanted to change the cost? Also, I could put the cost in a constructor, but if I wanted to change the cost I would still have to redeploy so does that really matter?
Contract deployment is very costly and you typically want to avoid it whenever possible. You would deploy a new contract when business rules change. For a simple state change operation like the one you described, you would want to provider a setter for the cost that uses the onlyOwner modifier to restrict access.
I have the following solidity code.
pragma solidity ^0.4.21;
contract Parent {
uint public childCount;
Child[] public children;
function makeChild(string name) external {
children.push(new Child(address(this), childCount, name));
childCount++;
}
function renameChild(uint index, string newName) external {
require(address(children[index]) != 0);
Child thisChild = Child(address(children[index]));
if (thisChild.isUpdated()) {
thisChild.rename(newName);
}
}
}
contract Child {
address parentAddress;
uint index;
string public name;
bool public isUpdated;
constructor(address parent, uint _index, string _name) public {
parentAddress = parent;
index = _index;
name = _name;
isUpdated = false;
}
function rename(string newName) external {
name = newName;
}
function renameViaParent(string updateName) external {
isUpdated = true;
Parent(parentAddress).renameChild(index, updateName);
}
}
I have been testing this code via Remix Solidity IDE. When I run in Javascript VM, I can create a child from parentInstance.makeChild("childName") and rename it using childInstance.renameViaParent("newName").
However when I switch to an Ethereum private chain, i.e. Injected Web3, I can still create the child, but fail in renaming using childInstance.renameViaParent("newName"). It gives the message:
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
Invalid JSON RPC response: {"id":1830,"jsonrpc":"2.0","error":{"code":-32603}}
I tried to remove thisChild.isUpdated() condition check in renameChild(index, newName) and the code ran fine in both JS VM and private Web3. This is why I believe accessing the member variable isUpdated of Child from Parent is causing the problem.
What is wrong here? Probably with my private chain set up? How is it different from the Javascript VM Remix is using?
I am using geth-linux-amd64-1.8.6-12683 to run my private chain.