Microservices Manager

While linked to an organization, the Microservices Manager is an active Component; it can read and write on (link, replace, un-link) other Components (by executing microservice code) as well as on the Organization's core.

A microservice is an external smart contract that can be called by the Microservices Manager using a low-level solidity call (staticcall and call) to carry out something specific on or on behalf of the Organization. During execution, a microservice acts as an active one-time Component; as discussed elsewhere, only an active Component can write on or for the Organization.

Only active (i.e authorized) components can write and execute microservices.

Each microservice is represented by a Microservice struct, composed as follows:

  • string key -> this represents the microservice's name, which is also its key

  • address location -> this represents the contract address of the microservice on which you want to perform operations.

  • string methodSignature -> this represents the signature of the microservice's method; i.e the name of the function that contains the parameters passed to the string methodSignature function for execution if execution (read / submit) of the microservice's code is required. This makes it possible to have only one Contract containing several microservices passing the methodSignature of the method that you want to use.

  • bool submittable -> this represents if the microservice is submittable (true) or readable (false). In the first case, its code can be executed by calling the submit method that use a low-level call; in the second, it can be executed by calling the read method that uses a low-level staticcall.

  • string returnAbiParametersArray -> this represents the return type of the microservice (bool, array, etc..). It can be used by a frontend to better classify the arrays of bytes incoming from the microservice.

  • bool isInternal -> this represents if the microservice can be called only by another microservice (true) or also by an external source (false), for example another Component of the organization. An internal microservice (isInternal is true) can only be submittable, not readable.

  • bool needsSender -> this represents whether you want to preserve the original msg.sender of the microservice (true) or not (false). The msg.sender is always the MicroservicesManager; a user or contract that acts on a microservice only ever does so through--and is thereby only ever the msg.sender of--the MicroservicesManager. If needsSender is true, the original msg.sender (i.e, the user / contract) is known by and available to the microservice, if ever required by it for one of its function or operations.

When a microservice is added to the organization via the MicroservicesManager, its key (i.e name) is linked to an index (uint256) by which it will be managed (e.g. retrieved and removed), and is saved in the MicroservicesManager contract using _index mapping.

The MicroservicesManager supports adding and removing data in batch mode; multiple microservices can be added or removed in a single transaction.

Microservice Code Execution

Microservice code can be executed in two ways.

Read

The read code execution mode allows a Microservice to read data from the chain (from other Microservices or Components for example) but not to write, using the read method. The read method is a utility method that uses a low-level solidity call function.

Read code execution mode allows a microservice to read data from the chain (e.g. data relating to other microservices or Components), but not write.

This mode can be useful for retrieving data that are either not available via a specific view function, or that are available, but not in the desired form (e.g. in the available view function some unwanted operations are done on the data).

The read execution is performed using the read function:

function read(string calldata key, bytes calldata data) external view returns(bytes memory returnData);

It takes as input:

  • string key -> represents the key of the Microservice to call

  • bytes data -> represents a payload to pass

The read is executed by calling the smart contract of the passed microservice and performing a staticcall on it passing the data. The function returns the output returnData.

A Microservice executed in read mode is not any kind of Component; it does not even become a one-time Component.

Submit

The submit code execution mode allows a microservice to write data on the chain, and conduct transactions that involve other Components of the other organization as well as any other elements of the Organization in general.The submit method is a utility method that uses a low-level solidity staticcall function.

The submit code execution can be called by anyone, the submit function is external with no modifier, because a microservice should be a pre-coded function that performs that specific task each time it is called.

For example, a submittable microservice can be a smart contract function allowed to send tokens from the Organization to its farming extension/Farming Manager when creating farming contracts.

The submit execution is performed using the submit function:

function submit(string calldata key, bytes calldata data) external payable returns(bytes memory returnData);

It takes as input:

  • string key -> represents the key of the Microservice to call

  • bytes data -> represents a payload to pass

The submit is executed by calling the methodSignature of the passed smart contract microservice passing the data. The function returns the output returnData.

payload = abi.encodePacked(bytes4(keccak256(bytes(microservice.methodSignature))), data);

The submit function is also a payable function, because it can receive from the microservice ETH that will be sent to the treasury. This means it's possible to create payable **

A microservice is not a normal Organization Component. However, a submittable microservice runs as a one-time active Component (i.e as a one-time submit) and is then immediately jettisoned. The temporary Component has a random temporary key that is not logged in the Organization.

bytes32 randomKey = BehaviorUtilities.randomKey(_keyIndex++);
organization.set(IOrganization.Component(randomKey, location, true, false));
returnData = location.submit(0, payload);
organization.set(IOrganization.Component(randomKey, address(0), false, false));

So a submittable Component becomes temporary an authorized Component that can act on the Organization executing its code.

As a highly customizable structure, if the Organization, for whatever reason, no longer wants to manage microservices, it can un-link the Microservices Manager Component from itself.

If un-linked, the Microservices Manager loses the right to attach temporary Components to the Organization. In fact, although the Microservices Manager still has the "Organization" variable saved, the Organization no longer can "know" the Microservices Manager.

Last updated