Securitize-DS Protocol
まとめ
Dizital Securityのオープン規格を謳っているが、 拡張性、オープン性が現実存在しているかは疑問
DS Protocolは誰でも使えるSTO総合プラットフォームを目指している
DS Appsを開発すればどの分野のプレイヤーも参加可能
発行プラットフォーム、取引所、 KYCベンダー 等
DS Protocol外のDS Appsは自由に設計が可能
Securitize platformはあくまで複数のDS Appsを有した1アクターでしかない
Issuing Apps、Dividend Apps、Voting DS Apps
他のプラットフォーム規格もDS Protocolを通じて参加可能
ST20, R-Token、ERC-884, S3 Protocol等に対応
Compliance ServiceのAdaption Layerが仲介
詳細は不明(誰か知ってる人がいたら教えていただきたい)
どの部分がDS Protocolの外で行われて、どの部分がDS Protocolを噛む必要があるのか、整理してみていくとよい
一方で、オープン規格を謳う割に、データの公開度が低く結局集権的なエコシステムになる可能性もある
ソースコードが公開されていないっぽい
どのようにしてプレイヤーをDS Protocolに参加させるか、インセンティブ設計も無し
実力あるプラットフォームが個別にプレイヤー参画を促すしか現在なさそう
既存金融を代替するためまずは集権的な設計からということか?
この状況で他のプレイヤーが優れたDS Appsを開発するのは難しそう
これが、オープンなものになっていくかはSecuritize次第感ある
良いSTO案件をという点でいえば、現状1,2を争うイケてるプラットフォームではあると思う(私見)
ネットワーキングや商品設計が他社よりイケてるから
ケーススタディまで出してる
集権的な方が、案件作るまでは早い
DS Ecosystem概観
Securitize はDS Serviceというインフラを提供
このインフラを利用して、各プレイヤーはDS Appsを作成
各Appsと DS Serviceとを仲介するのがDS Protocol
DS Protocolは統一規格となっている
各プレイヤーは目的に沿うDS Appsを作成
DS Protocol外なら自由にコントラクトを設計可能
https://gyazo.com/fe3bab751767ab1d7d75634227af71dfDSエコシステム概観
DS Ecosystemの登場プレイヤー
DS Tokens: ERC-20, DS Protocol規格に沿ったトークン
transfer(), transferFrom()関数: Compliance Serviceの情報に従ってwalletを認証
その他DSに必要な関数も整備
発行体による譲渡制限関数
配当関数 等
詳細コードは不明っす(スマソ)
発行体は、Securitize Issuance platformを通じて発行することもできるし、第三者が提供するApps群を利用して発行することも可能
私見:ココがオープンプロトコルたる所以だが、Securitize以外の第三者にそれが可能なのかは疑問符
DS Apps: Smart Contracts、DSの各イベントが発生をさせるコントラクトを書く
各プレイヤーが独自に設計可能
DS Protocolの外側に存在するため
ブロックチェーンとのインターフェースを構築
DS Service:Securitizeが設計した統一プロトコル
Trust Service:各DS Appのリクエストが実行可能かチェック
すべてのDS serviceに影響を与える
稼働 例:
Registry Serviceへの追加データ記入の可否を判断
Registry Service内のデータ変更が可能なETHアドレスを判断
Serviceそのものの利用可否を判断
ほとんどの場合、他の関数で条件が与えられているためこのServiceが作動することはあまりない
Compliance Service: トークン譲渡が適法に行われるかを監視
transfer(), transferFrom()関数に従ってRegistry Serviceを参照
投資家数の管理
投資家国別人数管理
取引量管理
Registry serviceの情報が関数の条件に合わない場合譲渡を制限
Comms Service: 投資家間のコミュニケーションを実現
配当情報等を通知可能
取引所等を通じて広がった投資家の管理を一元化
Registry service: 投資家情報on-chainで管理
登録情報:
国籍
KYC情報
Accredited investor or not
KYC期限
Accredited期限
KYC情報のハッシュ値
Accredited情報のハッシュ値
複数のwalletを一人の投資家に結びつけることが可能
他のサービスもRegistry Serviceを参照することが可能
ハッシュ値に加えて、KYC、Accreditedの結果もあえてそのままon-chainに乗っけておいているから
私見:誰でも検証可能を意味するので、プライバシーの観点から課題は残りそう?
Compliance serviceは監視の際にここを参照
Comms Service: 発行体の情報をトークン保有者に伝えるサービス
配当時等、これを呼び起こせばセカンダリーを通じて入手したトークン保有者にも情報が届く
私見:このService必要か…??DS Tokenに紐づいた情報だけで十分ではないのか?
RFE API: off-chain上で取引所がDS Serviceに連携するためのAPI
発行体が取引所からKYC情報を獲得することが可能
一度行ったKYCの使いまわしを実現か(?)
プライバシーに配慮してoff-chainにしている
https://gyazo.com/0f1e8970238bbb599f231d1cfc2e305dDS Protocol Ecosystem詳細
実例を用いた、プロトコル詳細解説
1: 発行
Issuing Appsにアクセスする(例ではSecuritize Issuing platform)
DS Protocolの外側で発生
Issuging Appsを通じて投資家は参加者登録
これもApp上で行われる。DS Protocolは関与しない。
投資家情報をRegistry Serviceへ保存する
DS Protocolを通じてブロックチェーン上に記載
registerInvestor()関数を利用
トークン発行
DS Protocolを通じて、Registry ServiceとDS Tokenの保有者とを結びつける
https://gyazo.com/08ea9dc7aa5f6bfb098cc63a3a1556dd発行プロセス詳細
2: 配当発行
発行者はプラットフォームへ配当を行う旨を伝え予算を送付
Dividend Appsを扱えるのは基本プラットフォームのみのため
プラットフォームはDevidend AppsへissueDividends()関数を送付
ここまではDS Protocolの外側で行われているので自由に設計可能
プロトコル外、なので違う関数を利用してもよい
Devidend AppsはDS Tokenへ投資家リストを参照
DS Protocolを通じて行われるので規格化されている
どういう関数使うのかは分からなかったンゴ
Devidend Appsは各投資家へ配当を送付
DS Protocol外で行われるので自由に設計が可能
場合によってはDevidend Appsはregistry Serviceにアクセスする
投資家確認を行いたい場合 等
Dividend AppsはComms Serviceへ配当情報を通知
投資家に情報を伝えるため
DS Protocolを通じて行われているので通知方法は定型化
notify()関数
Comms Serviceは情報を投資家へ通知
投資家は配当を受け取っていない場合、Dividend Appsへwithdrow()関数を通知
DS Protocolの外側なのでプラットフォーム毎に違う関数を作ってもよい
https://gyazo.com/ac41b417a48ab0d8df09761f665595cd配当プロセス
3:Voting Process
発行体はプラットフォームへ投票を行うことを通知
プラットフォームはVoting DS AppsへproposeVote()関数を送付
DS Protocolの外側で行われているので関数は自由に設計可能
Voting DS AppsはDS Tokenへ投資家リストを参照
関数は分からなかったンゴ
Protocolを介在するので規格化はされている
Voting DS AppsはComms Serviceを通じて議決内容を通知
Comms Serviceは議決内容をInvestorへ通知
各投資家はvote()関数で投票
DS Protocolの外側なので関数、UIはAPPごとに自由な設計が可能
スマートコントラクトを利用した投票
発行体は発行プラットフォームへ投票クロージングを通達
自動的にクローズするトリガーをスマートコントラクトに埋め込んでいる場合も有
プラットフォームはVoting DS appsへcloseVote()関数を送付
DS Protocolの外側なので自由に設計が可能
DS Voting Apps はDS Tokenを参照しつつ投票結果を集計
各投資家×トークン保有数を勘定
DS Protocolを通じて行われるので定型化
具体的な関数は分からなかったンゴ
AppsはComms Serviceを通じて投資家へ情報を通達
https://gyazo.com/d2fefc3f27a08c3237f06bb6dfdd4df6投票プロセス
4取引所:各取引所の特徴に従って設計方法が異なる
P2P間の直接の譲渡の場合:
Compliance serviceを通じたチェックを独自で行う
参加者各自でDS Protocolを通じてCompliance serviceへアクセスする必要アリ
Registry Serviceに登録されている投資家しかP2P取引に参加不可
registerInvestor()の使用権限はIssuerより制限されているので、もともと登録されていない投資家は参加不能
非中央集権取引所 :AirSwap型←Securitize的にはこの類型の取引所を推したいっぽい
新規希望投資家は取引所へ投資家情報を提供
取引所はregisterInvestor()関数をRegisty Serviceへ通知
DS Protocolを介するので規格化されている
Issuerより権限が与えられた取引所のみ参加可能
registerInvester()関数の使用権原がIssuerによって制限されるから
売りたい既存投資家と買いたい投資家とをマッチさせる
マッチ方法については各取引所のプロトコルに依存
取引所はDS TokenへtransferFrom()メソッドを走らせて所有権移転を実施
DS Protocolを通すため定型化されている
DS Tokenがtransfer()メソッドとtransferFrom()メソッドとを走らせる
DS Protocolを通すため定型化されている
DS TokenはValidate()関数をCompliance Serviceへ通知
DS Protocolを通すため定型化されている
Compliance Serviceがregistry Serviceを参照して条件を満たすか判断
DS Protocolを通すため定型化されている
https://gyazo.com/d6d2eb132a4ce9f9b29666b14e553a46分散型取引所プロセス
中央集権型(ウォレット投資家保持型)
基本的に非中央集権型とプロセスは同じ
ウォレット管理業務が追加される
中央集権型(ウォレット集権型):bitflyer等のスキーム
あまり推奨されていない方法(ホワイトペーパーで明示されている)
off-chainでの投資家管理は不透明性が多いため
取引所wallet内にslotsを設計させる
slots内にはTokenの条件に従う投資家しか入れさせない
Compliance serviceはslotsの管理を行う
他のプラットフォームとの連携
他の規格が有する問題点:
各プレイヤーのみに対応していてセキュリティトークンエコシステムの包括的な規格が存在しない
ユーティリティトークンを必要とする規格も存在
ST20はPolyトークンを必要とする、等
セキュリティトークンに合わないインセンティブ設計が行われる可能性
各規格、取引所に対してコンプラ制限を与えられていない
他規格の変換方法
Adoption Layerを通じて他規格を変換可能:
Compliance Service内に設置
実用例:
R-Tokenの場合:
Adaption Layerを通じてTransfer()関数ではなく、check()関数をCompliance Serviceへ通知
Service はRegulation Serviceを参照
R-Tokenのサービス
ST20の場合:
同様にverifyTransfer()をCompliance Serviceへ通知
ServiceはTransfer Managerを起動
ST20のサービス
他規格をDS Appsを通じて利用した場合、Utility Tokenを利用することなくSTOを行うことが可能になる
Codeが公開されたので色々見る
VersionedContract
全体として謎
code:VersionedContract(javascript)
pragma solidity ^0.4.23;
contract VersionedContract {
uint[] internal VERSIONS = 1; function getVersion() public view returns (uint[]) {
return VERSIONS;
}
}
Tomato.icon<う~~ん、謎!w
DSTokenInterface
DSトークンのインターフェースを規定
Tomato.icon<各関数で理由を説明する引数がuintではなくstringで設定されているのが他と違って面白いよ。理由が文字でそのまま入れられるのは利用者にとってはあり難いね
code: DSTokenInterface
pragma solidity ^0.4.23;
import "../../zeppelin/token/ERC20/ERC20.sol";
import "../util/VersionedContract.sol";
contract DSTokenInterface is ERC20, VersionedContract {
constructor() internal {
VERSIONS.push(1);
}
string internal constant CAP = "cap";
string internal constant TOTAL_ISSUED = "totalIssued";
string internal constant TOTAL_SUPPLY = "totalSupply";
string internal constant BALANCES = "balances";
string internal constant INVESTORS = "investors";
string internal constant WALLET_LIST = "walletList";
string internal constant WALLET_COUNT = "walletCount";
string internal constant WALLET_TO_INDEX = "walletToIndex";
string internal constant PAUSED = "paused";
event Issue(address indexed to, uint256 value, uint256 valueLocked);
event Burn(address indexed burner, uint256 value, string reason);
event Seize(address indexed from, address indexed to, uint256 value, string reason);
event WalletAdded(address wallet);
event WalletRemoved(address wallet);
/******************************
CONFIGURATION
*******************************/
/**
* @dev Sets the total issuance cap
* Note: The cap is compared to the total number of issued token, not the total number of tokens available,
* So if a token is burned, it is not removed from the "total number of issued".
* This call cannot be called again after it was called once.
* @param _cap address The address which is going to receive the newly issued tokens
*/
function setCap(uint256 _cap) public /*onlyMaster*/;
/******************************
TOKEN ISSUANCE (MINTING)
*******************************/
/**
* @dev Issues unlocked tokens
* @param _to address The address which is going to receive the newly issued tokens
* @param _value uint256 the value of tokens to issue
* @return true if successful
*/
function issueTokens(address _to, uint256 _value) /*onlyIssuerOrAbove*/ public returns (bool);
/**
* @dev Issuing tokens from the fund
* @param _to address The address which is going to receive the newly issued tokens
* @param _value uint256 the value of tokens to issue
* @param _valueLocked uint256 value of tokens, from those issued, to lock immediately.
* @param _reason reason for token locking
* @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)
* @return true if successful
*/
function issueTokensCustom(address _to, uint256 _value, uint256 _issuanceTime, uint256 _valueLocked, string _reason, uint64 _releaseTime) /*onlyIssuerOrAbove*/ public returns (bool);
function totalIssued() public view returns (uint);
//*********************
// TOKEN BURNING
//*********************
function burn(address _who, uint256 _value, string _reason) /*onlyIssuerOrAbove*/ public;
//*********************
// TOKEN SIEZING
//*********************
function seize(address _from, address _to, uint256 _value, string _reason) /*onlyIssuerOrAbove*/ public;
//*********************
// WALLET ENUMERATION
//*********************
function getWalletAt(uint256 _index) public view returns (address);
function walletCount() public view returns (uint256);
//**************************************
// MISCELLANEOUS FUNCTIONS
//**************************************
function isPaused() view public returns (bool);
function balanceOfInvestor(string _id) view public returns (uint256);
function updateInvestorBalance(address _wallet, uint _value, bool _increase) internal returns (bool);
function preTransferCheck(address _from, address _to, uint _value) view public returns (uint code, string reason);
}
function setCap:発行トークン数設定
function issueTokens:トークン発行
function issueTokensCustom:制限譲渡付のトークン発行
Tomato.icon<制限譲渡の場合だけ関数分けてるの面白いw
function totalIssued:トータルの発行数を見る
function burn:バーン(ドーン)(ガシャーン)
function seize:強制移転用の関数
Tomato.icon<権限設定はこのコントラクトでは設定されていない。どこで設定されているんだろ
Compliance Service内のfunction validateSeizeで行われるっぽい
function getWalletAt:引数に入れたindexのウォレットアドレスを見る
function walletCount:トークンを持っているウォレットの個数を見る
function isPaused:謎
function balanceOfInvestor:引数に入れた_idのアカウントの総量をチェックする
function updateInvestorBalance:投資家の保有数を変化させる
Tomato.icon<どういう場合にこれが使われるのか、謎
function preTransferCheck:譲渡可否をチェックする関数
Tomato.icon<returnがなぜboolではなくuint codeなのかが不明。boolでいいじゃん、横にstring reasonあるし
DSServiceConsumerInterface
DS Protocol上の各組織を結びつけるコントラクトだよ
Tomato.icon<各seviceに関連するコントラクトなのはよくわかるんだけど、詳細にどう機能するのかが良くわからない...
code:DSServiceConsumerInterface(javascript)
pragma solidity ^0.4.23;
import "../trust/DSTrustServiceInterface.sol";
contract DSServiceConsumerInterface is VersionedContract {
constructor() internal {
VERSIONS.push(1);
}
uint public constant TRUST_SERVICE = 1;
uint public constant DS_TOKEN = 2;
uint public constant REGISTRY_SERVICE = 4;
uint public constant COMPLIANCE_SERVICE = 8;
uint public constant COMMS_SERVICE = 16;
uint public constant WALLET_MANAGER = 32;
uint public constant LOCK_MANAGER = 64;
uint public constant ISSUANCE_INFORMATION_MANAGER = 128;
uint public constant COMPLIANCE_CONFIGURATION_SERVICE = 256;
modifier onlyMaster {
assert(false);
_;
}
modifier onlyIssuerOrAbove {
assert(false);
_;
}
modifier onlyExchangeOrAbove {
assert(false);
_;
}
modifier onlyToken {
assert(false);
_;
}
modifier onlyIssuerOrAboveOrToken {
assert(false);
_;
}
function getDSService(uint _serviceId) public view returns (address);
function setDSService(uint _serviceId, address _address) public /*onlyMaster*/ returns (bool);
event DSServiceSet(uint serviceId, address serviceAddress);
}
DSTrustServiceInterface
Trust Serviceのインターフェースを提供
Trust Service:各サービスへのアクセス権限などを管理する機能(詳細は上述)
code:DSTrustServiceInterface(javascript)
pragma solidity ^0.4.23;
import '../util/VersionedContract.sol';
/**
* @title DSTrustServiceInterface
* @dev An interface for a trust service which allows role-based access control for other contracts.
*/
contract DSTrustServiceInterface is VersionedContract {
constructor() internal {
VERSIONS.push(1);
}
/**
* @dev Should be emitted when a role is set for a user.
*/
event DSTrustServiceRoleAdded(address _address, uint8 _role, address _sender);
/**
* @dev Should be emitted when a role is removed for a user.
*/
event DSTrustServiceRoleRemoved(address _address, uint8 _role, address _sender);
// Role constants
uint8 public constant NONE = 0;
uint8 public constant MASTER = 1;
uint8 public constant ISSUER = 2;
uint8 public constant EXCHANGE = 4;
string internal constant OWNER = "owner";
string internal constant ROLES = "roles";
/**
* @dev Allow invoking of functions only by the user who has the MASTER role.
*/
modifier onlyMaster() {
assert(false);
_;
}
/**
* @dev Allow invoking of functions only by the users who have the MASTER role or the ISSUER role.
*/
modifier onlyMasterOrIssuer() {
assert(false);
_;
}
/**
* @dev Sets or removes a role for a wallet. (internal)
* @param _address The wallet whose role needs to be set or removed.
* @param _role The role to be set. NONE (0) indicates role removal.
* @return A boolean that indicates if the operation was successful.
*/
function setRoleImpl(address _address, uint8 _role) internal returns (bool);
/**
* @dev Transfers the ownership (MASTER role) of the contract.
* @param _address The address which the ownership needs to be transferred to.
* @return A boolean that indicates if the operation was successful.
*/
function setOwner(address _address) public /*onlyMaster*/ returns (bool);
/**
* @dev Sets a role for a wallet.
* @dev Should not be used for setting MASTER (use setOwner) or role removal (use removeRole).
* @param _address The wallet whose role needs to be set.
* @param _role The role to be set.
* @return A boolean that indicates if the operation was successful.
*/
function setRole(address _address, uint8 _role) public /*onlyMasterOrIssuer*/ returns (bool);
/**
* @dev Removes the role for a wallet.
* @dev Should not be used to remove MASTER (use setOwner).
* @param _address The wallet whose role needs to be removed.
* @return A boolean that indicates if the operation was successful.
*/
function removeRole(address _address) public /*onlyMasterOrIssuer*/ returns (bool);
/**
* @dev Gets the role for a wallet.
* @param _address The wallet whose role needs to be fetched.
* @return A boolean that indicates if the operation was successful.
*/
function getRole(address _address) public view returns (uint8);
}
function setRoleImpl:wallet機能の操作を行う(?)
function setOwner:Master権限者の移転を行う
function setRole:謎
function removeRole:謎
function getRole:謎
Tomato.icon< the roll for a walletの意味が謎だから全体的に謎になっちゃう
DSRegistryServiceInterface
Registry Serviceのインターフェースだよ
Registry Service:投資家情報が登録されている場所
KYCチェックなどのベースになる
プライバシーにも対応
Tomato.icon<How?
Modifierの解説は読めばすぐわかるから省略
1投資家が複数walletを持てる前提になっているのは非常に興味深い
code:DSRegistryServiceInterface(javascript)
pragma solidity ^0.4.23;
import '../service/DSServiceConsumerInterface.sol';
contract DSRegistryServiceInterface is DSServiceConsumerInterface {
constructor() internal {
VERSIONS.push(1);
}
event DSRegistryServiceInvestorAdded(string _investorId, address _sender);
event DSRegistryServiceInvestorRemoved(string _investorId, address _sender);
event DSRegistryServiceInvestorCountryChanged(string _investorId, string _country, address _sender);
event DSRegistryServiceInvestorAttributeChanged(string _investorId, uint256 _attributeId, uint256 _value, uint256 _expiry, string _proofHash, address _sender);
event DSRegistryServiceWalletAdded(address _wallet, string _investorId, address _sender);
event DSRegistryServiceWalletRemoved(address _wallet, string _investorId, address _sender);
uint8 public constant NONE = 0;
uint8 public constant KYC_APPROVED = 1;
uint8 public constant ACCREDITED = 2;
uint8 public constant QUALIFIED = 4;
uint8 public constant PROFESSIONAL = 8;
uint8 public constant PENDING = 0;
uint8 public constant APPROVED = 1;
uint8 public constant REJECTED = 2;
modifier investorExists(string _id) {
require(isInvestor(_id));
_;
}
modifier newInvestor(string _id) {
require(!isInvestor(_id));
_;
}
modifier walletExists(address _address) {
require(isWallet(_address));
_;
}
modifier newWallet(address _address) {
require(!isWallet(_address));
_;
}
modifier walletBelongsToInvestor(address _address, string _id) {
require(keccak256(abi.encodePacked(getInvestor(_address))) == keccak256(abi.encodePacked(_id)));
_;
}
function registerInvestor(string _id, string _collision_hash) public /*onlyExchangeOrAbove newInvestor(_id)*/ returns (bool);
function removeInvestor(string _id) public /*onlyExchangeOrAbove investorExists(_id)*/ returns (bool);
function setCountry(string _id, string _country) public /*onlyExchangeOrAbove investorExists(_id)*/ returns (bool);
function getCountry(string _id) public view returns (string);
function getCollisionHash(string _id) public view returns (string);
function setAttribute(string _id, uint8 _attributeId, uint256 _value, uint256 _expiry, string _proofHash) public /*onlyExchangeOrAbove investorExists(_id)*/ returns (bool);
function getAttributeValue(string _id, uint8 _attributeId) public view returns (uint256);
function getAttributeExpiry(string _id, uint8 _attributeId) public view returns (uint256);
function getAttributeProofHash(string _id, uint8 _attributeId) public view returns (string);
function addWallet(address _address, string _id) public /*onlyExchangeOrAbove newWallet(_address)*/ returns (bool);
function removeWallet(address _address, string _id) public /*onlyExchangeOrAbove walletExists walletBelongsToInvestor(_address, _id)*/ returns (bool);
function getInvestor(address _address) public view returns (string);
function getInvestorDetails(address _address) public view returns (string, string);
function isInvestor(string _id) public view returns (bool);
function isWallet(address _address) public view returns (bool);
}
function registerInvestor:投資家新規登録時の関数
function removeInvestor:投資家削除時の関数
function setCountry:投資家の国籍を与える関数
国籍はstringで設定可能
function getCountry:国籍チェックの関数
function getCollisionHash:謎
function setAttribute:Attributeってなんや、、、
function addWallet:投資家にwalletを追加する関数
Tomato.icon<複数ウォレットを持てる前提になっているのは非常に面白い
金持ち投資家とか資産分別したり秘匿性高めるためにもwallet複数持ちたいニーズあるだろうからね
function removeWallet:walletを削除する関数
function getInvestor,function getInvestorDetails:投資家情報を得る関数
function isInvestor,function isWallet:投資家登録、ウォレット登録されているかをチェックする関数
DSComplianceServiceInterface
譲渡制限とかを管理するサービス
Interface読んだまんまだから解説は省略
code:DSComplianceServiceInterface(javascript)
pragma solidity ^0.4.23;
import "../service/DSServiceConsumerInterface.sol";
import "../../zeppelin/token/ERC20/ERC20.sol";
contract DSComplianceServiceInterface is DSServiceConsumerInterface {
constructor() internal {
VERSIONS.push(2);
}
uint internal constant NONE = 0;
uint internal constant US = 1;
uint internal constant EU = 2;
uint internal constant FORBIDDEN = 4;
string internal constant TOKEN_PAUSED = "Token Paused";
string internal constant NOT_ENOUGH_TOKENS = "Not Enough Tokens";
string internal constant TOKENS_LOCKED = "Tokens Locked";
string internal constant WALLET_NOT_IN_REGISTRY_SERVICE = "Wallet not in registry Service";
string internal constant DESTINATION_RESTRICTED = "Destination restricted";
string internal constant VALID = "Valid";
string internal constant TOTAL_INVESTORS = "totalInvestors";
string internal constant US_INVESTORS_COUNT = "usInvestorsCount";
string internal constant US_ACCREDITED_INVESTORS_COUNT = "usAccreditedInvestorsCount";
string internal constant ACCREDITED_INVESTORS_COUNT = "accreditedInvestorsCount";
string internal constant EU_RETAIL_INVESTORS_COUNT = "euRetailInvestorsCount";
string internal constant ISSUANCES_COUNT = "issuancesCount";
string internal constant ISSUANCE_VALUE = "issuanceValue";
string internal constant ISSUANCE_TIMESTAMP = "issuanceTimestamp";
string internal constant HOLD_UP = "Hold-up";
string internal constant HOLD_UP_1Y = "Hold-up 1y";
string internal constant ONLY_FULL_TRANSFER = "Only Full Transfer";
string internal constant FLOWBACK = "Flowback";
string internal constant MAX_INVESTORS_IN_CATEGORY = "Max Investors in category";
string internal constant AMOUNT_OF_TOKENS_UNDER_MIN = "Amount of tokens under min";
string internal constant AMOUNT_OF_TOKENS_ABOVE_MAX = "Amount of tokens above max";
string internal constant ONLY_ACCREDITED = "Only accredited";
string internal constant NOT_ENOUGH_INVESTORS = "Not enough investors";
//*****************************************
// TOKEN ACTION VALIDATIONS
//*****************************************
function validateIssuance(address _to, uint _value, uint _issuanceTime) /*onlyToken*/ public returns (bool);
function validateBurn(address _who, uint _value) /*onlyToken*/ public returns (bool);
function validateSeize(address _from, address _to, uint _value) /*onlyToken*/ public returns (bool);
function validate(address _from, address _to, uint _value) /*onlyToken*/ public returns (bool);
function preIssuanceCheck(address _to, uint _value) view public returns (uint code, string reason);
function preTransferCheck(address _from, address _to, uint _value) view public returns (uint code, string reason);
}
◆Source