Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
1 contributor

Users who have contributed to this file

349 lines (233 sloc) 10.8 KB
iip title author discussions-to status type category created
16
ICON Security Token Standard
Patrick Park (@cordiallys)
Draft
Standards Track
IRC
2019-01-21

Simple Summary

This document represents the standard protocol specification for the security token of ICON network.

Abstract

The security token standard describes how to represent full ownership or split ownership of a particular asset. This standard is compatible with standard IRC2 token IIP-2 and inspired by several security token standards such as EIP-1400, EIP-1410. A standard for the Partially Fungible Token (PFT) was additionally written for grouping tokens into partition sets, and each partition is represented by a key-value format consisting of a unique key and balance. Through this standard, ownership of certain assets can be divided and represented, tracked, viewed, privately owned and transferred. It may also be entrusted to a third party provider and may be controlled under strict authorization.

Motivation

The objective is to securitize and liquidate assets on the ICON block chain, by issuing and managing security tokens. The standard supports legal document asserting the rights of tokenized assets on a block chain, partition management with partially fungible tokens in tranche, and interfaces for managing operator privileges.

Rationale

Partition

A Partially-Fungible Token allows to attach metadata for a partial balance of a token holder. These partial balances are called partitions, which have an unique name, partial balance of token, etc.

Document Management

Since security tokens entails rights and oblications either from investor or the issuer, the ability to connect legal documents with the relevant contracts or partitions is importannt.

Check for Security Token Transfer

The transfer of security token may fail for a variety of reasons. The reasons for failure include the identity of the sender and the receiver whether they have passed the KYC or AML procedures, the maximum number of investors, the maximum holding ratio, and the lockup period of transfer. An interface is needed to check whether the security tokens are transferable before the transfer and to return the reason for failures.

Token Control by Operator

Security tokens may transfer or retrieve tokens and partitions from a regulatory authority or operator with regulatory consent even if they are not holders of the token. For example, if an investor has falsified the KYC/AML, an holder lost a key, or a fraud transaction needs to be restored, operator permission to control the tokens or partitions of other holders is needed.

Specification

1. Partially Fungible Token Interface

class PartiallyFungibleTokenStandard(ABC):

    @abstractmethod
    def name(self) -> str:
        pass

    @abstractmethod
    def symbol(self) -> str:
        pass

    @abstractmethod
    def decimals(self) -> int:
        pass

    @abstractmethod
    def totalSupply(self) -> int:
        pass

    @abstractmethod
    def balanceOf(self, _owner: Address) -> int:
        pass

    @abstractmethod
    def balanceOfPartition(self, _partition: str, _owner: Address) -> int:
        pass

    @abstractmethod
    def partitionsOf(self, _owner: Address) -> dict:
        pass

    @abstractmethod
    def transfer(self, _partition: str, _to: Address, _value: int, _data: bytes) -> None:
        pass

Methods

name

Returns the name of the token.

@external(readonly=True)
def name(self) -> str:

symbol

Returns the symbol of the token.

@external(readonly=True)
def symbol(self) -> str:

decimals

Returns the number of decimals to the token uses

@external(readonly=True)
def decimals(self) -> int:

totalSupply

Returns the total token supply

@external(readonly=True)
def totalSupply(self) -> int:

balanceOf

Retruns the account balance of an account with address _owner.

@external(readonly=True)
def balanceOf(self, _owner: Address) -> int:

balanceOfPartition

Returns the balance of the partition with _partition.

@external(readonly=True)
def balanceOfPartition(self, _partition: str, _owner: Address) -> int:

partitionsOf

Returns the partition information of an account with address _owner. The information of partition consists of a unique key with _name and token amount in partition with _amount

@external(readonly=True)
def partitionsOf(self, _owner: Address) -> dict:

transferByPartition

Transfers _partition to a specific account with _to. You should call self.msg.sender when the _amount of the _partition is sufficient. The @eventlog should be called on transferByPartition call. ( See implementation as below). The transferByPartition method can be managed by the operator specified in the Security Token Standard below.

@external
def transferByPartition(self, _partition: str, _to: Address, _amount: int, _data: bytes = None) -> None:

canTransferByPartition

Returns the reason of failure when partition transfer. Transfers of partition may fail for a number of reasons, such sender or receiver who have not passed the KYC/AML process, users who are in the transfer lockup period, the maximum number of investors has been reached.

@external
def canTransferByPartition(self, _partition: str, _to: Address, _amount: int, _data: bytes = None) -> str:

2. Security Token Standard Interface

class SecurityTokenStandard(PartiallyFungibleTokenStandard):

    @abstractmethod
    def setDocument(self, _name: str, _uri: str, _document_hash: str) -> None:
        pass

    @abstractmethod
    def getDocument(self, _name: str) -> dict:
        pass

    @abstractmethod
    def isControllable(self) -> bool:
        pass

    @abstractmethod
    def isIssuable(self) -> bool:
        pass

    @abstractmethod
    def issue(self, _partition: str, _owner: Address, _investor: int, _data: bytes) -> None:
        pass

    @abstractmethod
    def redeem(self, _partition: str, _investor: Address, _amount: int, _data: bytes) -> None:
        pass

    @abstractmethod
    def authorizeOperator(self, _operator: Address) -> None:
        pass

    @abstractmethod
    def authorizeOperatorForPartition(self, _owner: Address, _partition: str, _operator: Address) -> None:
        pass

    @abstractmethod
    def revokeOperator(self, _operator: Address) -> None:
        pass

    @abstractmethod
    def revokeOperatorForPartition(self, _owner: Address, _partition: str, _operator: Address) -> None:
        pass

    @abstractmethod
    def isOperator(self, _operator: Address) -> bool:
        pass

    @abstractmethod
    def isOperatorForPartition(self, _owner: Address, _partition: str, _operator: Address) -> bool:
        pass

Methods

setDocument

Sets information of document identified by the unique with _name. Raw documentation is organized in offchain. _uri and _document_hash are stored in blockchain to prevent forgery and falsification.
Examples of documents may include legal rights, transfer provisions, sales term, etc. in connection with a security type token.

@external
def setDocument(self, _name: str, _uri: str, _document_hash: str) -> None:

getDocument

Returns information of document with _name.

@external(readonly=True)
def getDocument(self, _name: str) -> dict:

isControllable

Returns whether token is controllable.

@external(readonly=True)
def isControllable(self) -> bool:

isIssuable

Returns whether token is issuable.

@external(readonly=True)
def isIssuable(self) -> bool:

issue

Distributes the issued token to _investors through _partition as _amount. Specific metadata can be treated with _data. _partition should be issued as _amount within the totalSupply quantity, The _partition and balance quantity of the _investor must be changed together. The issue method must be controlled by the Operator as below.

if self.isIssuable() and self.isOperator(self.msg.sender):
#issue

The @eventlog for this method should be triggered when calling the issue method.

def issue(self, _partition: str, _investor: Address, _amount: int, _data: bytes) -> None:

redeem

Redeems the _partition of a specific account by _amount. At the time of redemption, _investor’s __partitions should be reimbursed by _amount and _investor’s total balance should also be changed. The redeem method must be controlled and issued by the operator. When invoking the redeem method, @eventlog for this method should be triggered.

def redeem(self, _partition: str, _investor: Address, _amount: int, _data: bytes) -> None:

authorizeOperator

Grants _operator access control to issued token. The _operator and self.owner can control the token. The @eventlog must be triggered when granting access control.

def authorizeOperator(self, _operator: Address) -> None:

authorizeOperatorForPartition

Grants _operator the _partition access control of _owner. The @eventlog must be triggered when granting access control.

def authorizeOperatorForPartition(self, _owner: Address, _partition: str, _operator: Address) -> None:

revokeOperator

Revokes the access granted from _operator. Only self.owner and _operator can call this method. The @eventlog must be triggered when revoking access control.

def revokeOperator(self, _operator: Address) -> None:

revokeOperatorForPartition

Revokes the _partition access control of _owner from _operator. Only self.owner and _operator can call this method. The @eventlog must be triggered when revoking access control.

def revokeOperatorForPartition(self, _owner: Address, _partition: str, _operator: Address) -> None:

isOperator

Returns whether _operator has access control to token.

@external(readonly=True)
def isOperator(self, _operator: Address) -> bool:

isOperatorForPartition

Returns whether _operator has access control to _partition of `_owner.

@external(readonly=True)
def isOperatorForPartition(self, _owner: Address, _partition: str, _operator: Address) -> bool:

Implementaion

After completing audit process, it will be released officially.
https://repo.theloop.co.kr/sto/icon-sto-standard/tree/master/score

Copyright

Copyright and related rights waived via CC0.

You can’t perform that action at this time.