1

Follow up on: Web3J: TypeError: MyContract is not a constructor

Here is how my contract looks like:

contract OrganisationsFactory {
    mapping(string => OrganisationObject[]) organisations;
    event CreatedOrg(address indexed hsAddr);

    function add(string name, string vat, string headquaterAddress) public returns(address) {
        OrganisationObject newOrg = new OrganisationObject(name, vat, headquaterAddress);
        organisations[name].push(newOrg);
        CreatedOrg(newOrg);
        return newOrg;
    }

    function get(string name) public returns(OrganisationObject[]){
        return organisations[name];
    }
}

contract OrganisationObject {
    struct organisationDetails {
        string name; 
        string vat; 
        string headquaterAddress;
    }

    organisationDetails public details;

    address[] public staff;

    function OrganisationObject (string name, string vat, string headquaterAddress){
        details.name = name;
        details.vat = vat;
        details.headquaterAddress = headquaterAddress;
    }

    function addStaff(address x){
        staff.push(x);
    }
}

My aim is to create a contract on the chain containing the details of an organisation, to then be retrieve in the future. Basically just like a database. If I follow your approach I will compile a new contract every time, I will therefore never know where is my "organisation" kept unless I keep a reference to it contract in a conventional database.

Is there a better way then my approach to deal with this ?

4

Couple of ideas that might help simplify this and reduce the cost by removing redundant storage.

This line:

mapping(string => OrganisationObject[]) organisations;

seems heavy. I would incline to just let the factory be a factory and track just the contract addresses it creates; no unnecessary details. I changed it to an address[].

I'm a little leery about string arguments, but it seems to be working. Strings are more costly, and also why the event logs aren't easy to interpret. I would incline to changing all the strings to bytes32. This would be lower gas cost and more "native" for ethereum. Convert strings to/from bytes32 on the client side.

The newOrg contract is directly convertible to a type address, so I'm just keeping track of addresses in the factory. Added two simple functions so a client can browse the list. There is going to be less storage in the factory due to not recording every detail of the organizations created.

I think it's good policy to include the args passed in the events that get emitted.

pragma solidity ^0.4.6;

contract OrganisationsFactory {
    address[] organizations;
    event LogCreatedOrg(address indexed hsAddr, string name, string vat, string headquarterAddress);

    function add(string name, string vat, string headquarterAddress) public returns(address) {
        OrganizationObject newOrg = new OrganizationObject(name, vat, headquarterAddress);
        organizations.push(newOrg);
        LogCreatedOrg(newOrg, name, vat, headquarterAddress);
        return newOrg;
    }

    function getOrgAtIndex(uint index) public constant returns(address org){
        return organizations[index];
    }

    function getOrganizationCount() public constant returns(uint count) {
        return organizations.length;
    }
}

contract OrganizationObject {

    struct organizationDetails {
        string name; 
        string vat; 
        string headquarterAddress;
    }

    organizationDetails public details;

    address[] public staff;

    function OrganizationObject (string name, string vat, string headquarterAddress){
        details.name = name;
        details.vat = vat;
        details.headquarterAddress = headquarterAddress;
    }

    function addStaff(address x){
        staff.push(x);
    }
}

We can create an Org:

enter image description here

Then get an Org count and retrieve the Org addresses:

enter image description here

Then instantiate the contract at the Org's address:

enter image description here

And see the Org details:

enter image description here

Hope it helps.

Update: Some simple storage patterns here: Blog: Simple Storage Patterns in Solidity

  • This is great ! thank you very much, so from my front end using web3 I would just need to call for the organisation contract address and get all the details ? – Rémi Mar 2 '17 at 11:26
  • I am now stuggeling to access the stuct organizationDetails from my front end. Here is how i have been trying but it does not seem to work: var MyContract = web3.eth.contract(abi.abiOrganisationObject).at(address); var details = MyContract.details(); res.end(details).status(200) – Rémi Mar 2 '17 at 12:15
  • 1
    Exactly. You can even call for the count from the factory, and then for(i=0; i<count; i++) { // get one address from the factory // do stuff with the org contract at that address ... } – Rob Hitchens - B9lab Mar 2 '17 at 12:18
  • right but it does not work, i get a javascript error: TypeError: First argument must be a string or Buffer, from what i read online I think i need to add a callback in MyContract.details(), however I am not sure what to put in that callback. – Rémi Mar 2 '17 at 12:20
  • You're right. It's about callbacks. It's not working because it's not waiting for the response before it outputs the result. If you haven't seen callbacks before, they will deserve some orientation. Suggest opening another question or research on this topic so the comment thread doesn't go off topic. – Rob Hitchens - B9lab Mar 2 '17 at 12:33
1

You do not have to compile a new contract every time. That is only to deploy a new contract. Once that transaction is mined, the contract is assigned an address. Then any machine on the network can get an object to call the contract methods on, knowing the ABI and the contract's assigned address.

var myContractInstance = eth.contract(ABI).at(Address);

Contract methods can be called on the above myContractInstance variable. Consider it a handle or pointer to the same single contract that was deployed at Address earlier.

Ref: See https://www.ethereum.org/greeter

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.