Skip to content
Charles Plant St.Louis edited this page Nov 9, 2018 · 15 revisions

Welcome to the polymath-core wiki!

Polymath Protocol

ST20 standard (interfaces/IST20.sol)

The ST20 interface builds on top of the ERC20 standard to provide a new standard for security tokens. It provides one additional method, which can be used on-chain for other contracts to check whether a specific token transfer (or transferFrom) transaction is allowed:

function verifyTransfer(address _from, address _to, uint256 _amount) public view returns (bool success);

A token which implements this standard must provide an implementation of this function, which always returns either true or false, and does not throw. Furthermore the transfer and transferFrom functions must respect the outcome of this function, and only succeed if this function returns true. Note that a transfer or transferFrom call may still throw or return false if verifyTransfer returns true, but if verifyTransferreturnsfalse`, they must not succeed.

As an example, a ST20 token which only allows transfers between known addresses, should return false unless the transfer is between know addresses, otherwise it should return true.

This allows other contracts to check whether a token transfer is valid before actually executing the transfer.

The standard also requires every token to implement a mint function that is used to issue the token:

function mint(address _investor, uint256 _amount) public returns (bool success);

SecurityToken (contracts/tokens/SecurityToken.sol)

This is the first Polymath implementation of an ST20 token. It fulfils the ST20 standard, and provides some additional functionality on top of this standard.

This contract allows delegation of certain types of functionality (permissions, transfer restrictions and fund raising) to modules that can be attached to the SecurityToken contract.

Future versions of SecurityToken will provide other types of module functionality (e.g. governance, dividends, reporting) in a similar fashion.

Modules

A module is a contract that encapsulates a self-contained piece of functionality related to a Polymath security token.

Every module must be created via a factory contract, that conforms to interfaces/IModuleFactory.sol. Module Factories provide certain basic information about the modules which they create, and are attached to a SecurityToken and are also responsible for instantiating and initialising their associated modules.

Module Factories are registered in the ModuleRegistry by their creators.

IModuleFactory provides an interface to provide this standardised information and deployment functionality.

getType

function getType() public view returns(uint8);

This should return the type of module. Currently defined types are:

uint8 public constant PERMISSIONMANAGER_KEY = 1;
uint8 public constant TRANSFERMANAGER_KEY = 2;
uint8 public constant STO_KEY = 3;

which will be extended in future versions.

Description of Module

The module factory provides several helper functions for UIs to understand the details of a given module:

function getName() public view returns(bytes32);
function getDescription() public view returns(string);
function getTitle() public view returns(string);
function getInstructions() public view returns (string);

These should return human readable constants for the given module.

Cost

Each module can have an associated charge in POLY that is levied by the module factory, and paid by the SecurityToken in order to attach the module to a security token.

The basic Polymath provided modules have a 0 cost, but third parties are free to charge POLY to attach their modules.

The function:

function getCost() public view returns(uint256);

should return the cost to attach a module.

Deployment

In order to create a module, and attach it to a SecurityToken, the module factory must implement a deploy function which takes initialisation arguments, and returns the address of the newly created module:

function deploy(bytes _data) external returns(address);

The initialisation arguments are provided as a generic bytes _data. This data defines both the initialisation function in the newly created module, and the arguments to this function. As an example, an STO module may have an initialisation function configure, which takes a uint256 _startTime parameter. In this instance, the first part of _data is the function signature (e.g. bytes4(keccak256("configure(uint256)"))) and this is then followed by the _startTime value.

As an example, using the CappedSTOFactory, the deploy function is:

    function deploy(bytes _data) external returns(address) {
        require(polyToken.transferFrom(msg.sender, owner, getCost()));
        //Check valid bytes - can only call module init function
        CappedSTO cappedSTO = new CappedSTO(msg.sender);
        //Checks that _data is valid (not calling anything it shouldn't)
        require(getSig(_data) == cappedSTO.getInitFunction());
        require(address(cappedSTO).call(_data));
        return address(cappedSTO);
    }

The module factory should use the getSig function to check that the provided _data matches the named initialisation function and signature before using the low-level call method to call it.

In addition to creating the new module, the deploy function should also transfer any POLY fee required to deploy the module to the Module Factory owner. This is done via a call:
require(polyToken.transferFrom(msg.sender, owner, getCost()));

Ownership

The IModuleFactory.sol contract inherits from the OpenZeppelin Ownable.sol contract. The owner of the Module Factory will be the address that receives any POLY paid by the Security Token issuer to deploy or use the associated Module.

Module Factory Constructor

IModuleFactory.sol defines a simple constructor which should be called as part of the constructor of any implementing Module Factory. The only argument is the address of the POLY token, which is 0x9992eC3cF6A55b00978cdDF2b27BC6882d88D1eC.

Registering Modules

Once you have deployed your new Module Factory contract, you can register it in the ModuleRegistry so that it can be attached to Security Tokens.

Anyone can register a new module to the ModuleRegistry by calling:
function registerModule(address _moduleFactory) external returns(bool)
and passing the address of the Module Factory.

Although any module can be registered in the Module Registry, only Polymath verified modules are available for general use by all Security Tokens. Non-verified modules can only be used by Security Tokens with the same owner as the Module Factory, allowing issuers to create their own bespoke modules for their own use, without going through the Polymath verification process.

If you have a module you would like to be verified, please contact Polymath for detail requirements (e.g. audit, code review) to be verified.

Adding Modules

Once a module has been registered, it can be added to a SecurityToken by calling the function:

    function addModule(
        address _moduleFactory,
        bytes _data,
        uint256 _maxCost,
        uint256 _budget,
        bool _replaceable
    )

This function can only be called by the SecurityToken owner. In addition to the already discussed parameters, the function can specify an ongoing budget for the module. This can be used to pay on-going charges, such as KYC'ing individual investors.

It is possible to add up to 10 modules of the same type (e.g. up to ten separate TransferManager modules). How these modules are used is determined by the SecurityToken implementation. For example TransferManager modules are used to determine the result of verifyTransfer in SecurityToken.

Clone this wiki locally