4

Has there been any research into how a contract factory might be made in Michelson/Liquidity?

To elaborate, in Solidity a contract factory might look like:

pragma solidity ^0.4.8;

contract Bakery {

  // index of created contracts

  address[] public contracts;

  // useful to know the row count in contracts index

  function getContractCount() 
    public
    constant
    returns(uint contractCount)
  {
    return contracts.length;
  }

  // deploy a new contract

  function newCookie()
    public
    returns(address newContract)
  {
    Cookie c = new Cookie();
    contracts.push(c);
    return c;
  }
}


contract Cookie {

  // suppose the deployed contract has a purpose

  function getFlavor()
    public
    constant
    returns (string flavor)
  {
    return "mmm ... chocolate chip";
  }    
}

(referenced from https://ethereum.stackexchange.com/questions/13415/deploy-contract-from-contract-in-solidity)

This is a powerful feature in DAPP development, as it allows you to build an object oriented structure for your DAPP where requests can create new contracts. It is a well established design pattern, so what would the equivalent be in the Tezos ecosystem?

  • It appears like CREATE_CONTRACT { storage 'g ; parameter 'p ; code ... } would work, but this will bloat the size of a contract a bit, and it feels like there should be a way to handle this gracefully like in Solidity's Java style class instantiation. – Rob Mar 11 '19 at 23:54
  • If not, a clean example in Michelson would be nice. – Rob Mar 11 '19 at 23:56
  • ok cool, probably a ways out then. – Rob Mar 12 '19 at 0:24
  • 1
    I put a comment that I deleted to convert it into an answer. I missed your comment that was added afterwards. My apologies for this. – FFF Mar 12 '19 at 0:34
3

There is a very succinct discussion in the announcement for SmartPy https://medium.com/@SmartPy_io/introducing-smartpy-and-smartpy-io-d4013bee7d4e#15ee.

The idea is to have a contract that holds a big_map and each element of the big_map represents a contract.

This is absolutely not restricted to SmartPy and it is directly doable in Michelson, Liquidity or Fi.

This subject also appeared here: What is the BigMap container and why does it matter?

| improve this answer | |
  • I appreciate your response and don't want this to come across negative, but I feel we need to come up with a more comprehensive solution to this problem in the near term to make DAPP development productive. – Rob Mar 12 '19 at 7:35
  • I can easily agree that this is not the final and only solution. – FFF Mar 12 '19 at 11:52
  • reference below to see an example of what I was thinking – Rob Mar 14 '19 at 4:36
2

Here's an example of a contract handling this in liquidity. There's the unique challenge of writing functions that can only utilize remote procedure calls at the end of their execution:

type plus_storage = {
    count: nat,
    plus_owner: address,
  };

contract PlusOne = {
  type storage = plus_storage;
  let%init storage = (y: nat) => {
    count: y,
    plus_owner: Current.sender(),
  };
  let%entry main = (p: nat, storage) => {
    if (Current.sender() != storage.plus_owner) {
      failwith("invalid caller");
    };
    ([], storage);
  }
};

type storage = {
  owner: key,
  pl: address,
};

let%init storage = (contract_owner: key) => {
  owner: contract_owner,
  pl: KT1111111111111111111111111111111111,
}

let%entry other = (param: nat, storage) => {
  let t: option(PlusOne.instance) = Contract.at(storage.pl);
  let t = switch(t) {
    | None => Current.failwith()
    | Some(inst) => inst
  };
  let op = Contract.call(
    ~dest=t,
    ~amount=0tz,
    ~entry=main,
    ~parameter=param);
  ([op], storage);
};

let%entry main = ((), storage) => {
  let manager = Crypto.hash_key(storage.owner);
  let delegate = Some(manager);
  let spendable = false;
  let amount = Current.amount();
  let init_value: nat = 0;

  let (c_op, c_addr) =
    Contract.create(
      ~manager,
      ~delegate,
      ~spendable,
      ~delegatable=false,
      ~amount,
      ~storage={count: init_value, plus_owner: Contract.address(Contract.self())},
      (contract PlusOne),
    );

  let storage = storage.pl = c_addr;
  ([c_op], storage);
};

It makes me wonder if this will lead to endpoints that are like "order" and "pickup", ie a restaurant.

| improve this answer | |

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.