-
Notifications
You must be signed in to change notification settings - Fork 160
Home
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
verifyTransferreturns
false`, 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);
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.
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.
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.
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.
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.
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()));
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.
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
.
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.
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
.
CLI Installation
Running the CLI Features and Modules
- How to Use the POLY Faucet
- St-20 Generator
- STO Manager
- How to Use the Investor Portal
- Token Manager
- Transfer Feature
- Transfer Ownership
- Dividends Manager
- Transfer Manager
- Contract Manager
- Permission Manager
- Time Travel for Contract Testing
Modules
- LockupTransferManager
- VolumeRestrictionTransferManager
- BlacklistTransferManager
- ManualApprovalTransferManager
- CountTransferManager
- GeneralPermissionManager
- PercentageTransferManager
- GeneralTransferManager
- DividendCheckpointModules
- VestingEscrowWallet
- CappedSTO
- USDTieredSTO
- AdvancedPLCRVotingCheckpoint
- VotingCheckpointModules
- Schedule Checkpoint