R-Token Standard
まとめ
off-chainでチェックした結果を参考に譲渡制限をかけるシンプルな形
function transfer, function transferFromにfunction check関数を加えただけ
KYCやAccreditedの結果はon-chainには載せない
->既存判断者にoff-chainでかなり拠っている
Regulator毎にRegulator serviceが必要になる
各Addressをトークンが保有する
拡張性はあまりないと思案
Regulator Serviceの認証を与える機関が増えるシステムが見当たらない
ホワイトペーパー内ではTrade Controllerとして規定
最初はHarborのみがこの位置に就く
内容
現状の問題
Public Placement:流動性が高いが、コストも高い
情報公開義務が多い
企業管理が大量
Private Placement:コスト低いが、流動性も低い
法的制限があるため
その管理のために仲介者が多数存在するため
法的リスクがあるから簡単に移譲できない
->流動性の低さが価格を2~3割低くしている
Token Placement: コスト低いまま流動性を高めることが可能
仲介者を省ける
譲渡監視が簡単になる
ブロックチェーン上で公開されるため
https://gyazo.com/61e884e624244835ddc98e021b44c44f 現状の問題とR-tokenが実現することを4象限で表現
R-token Standard:三つのメイン要素から構成
R-Token:ERC20のtransfer関数をRegurator Serviceにアクセスするよう改編
仲介者無しの場合:
送信者は, function transferFromを呼び起こす(1)
function transferFrom内のfunction checkがRegulator Serviceを参照(2)
認証の有無をCheckStatusで返す(3)
NGだった場合は理由を返答できるようbiteで定義
認証された場合Transfer関数でトークンを移転
取引所を仲介する場合:
送信者はapprove関数を呼び起こす(1)
allocate関数はapprove関数内のトークン量を仲介者へ送信(2)
仲介者内で投資家をマッチ(3)
Transfer関数を投げてその中のCheck関数を呼ぶ(4,5)
認証された場合commit関数でAliceへ送信(6,7)
https://gyazo.com/eef9ff897b8c295862e2ca554036224b 仲介者無しの場合
https://gyazo.com/227a6967e0efa262ade8a462dbf77f7a 中央取引所を経由する場合
the Regulator Service:投資家が参加できるかをチェックするコントラクト
構成要素:function checkのみ
Input:
address _token: 送られるトークンのアドレス
address _spender:送信するアドレス
address _from:トークン原保有者のアドレス
address _to:トークン送信先のアドレス
uint256 _amount:トークン送付量
return:
uint 8: 結果を返答
譲渡制限に引っかかった場合、否定理由を返答
登録方法:ユーザ認証とトークン設定とを別レイヤーで設定
ユーザ認証:送信認証、受信認証
off-chain上で第三者機関がKYCやAccredited等を精査して両方の結果を返答
トークン設定:
譲渡制限:規制に適合したロックアップ期間を設定
国ごとにthe Regulator Serviceが設置される
各要素の投資家適合性はoff-chainで担当機関が判断&結果を記述
Service Registry:適切なRegulator Service Addressを付与
ここに登録されたAddressに従ってR-TokenはRegulator Serviceを参照
どこのthe regulator serviceを参照すればよいかがわかる
プロセス:
1:Service Registryは各Regulator Serviceのコントラクトアドレスを取得
2:Service Registry はR-tokenに対してそのアドレスを付与
R-tokenコントラクト内のfunction _service()によって実施
3:そのアドレスに従ってR-tokenは認証作業を実施(上述)
https://gyazo.com/5888960a00db9d82dafe2c404364d68a プロセス
インターフェース&Code
R-Token
code:RegulatedToken(javascript)
/**
Copyright (c) 2017 Harbor Platform, Inc.
Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.18;
import 'zeppelin-solidity/contracts/token/DetailedERC20.sol';
import 'zeppelin-solidity/contracts/token/MintableToken.sol';
import './ServiceRegistry.sol';
import './RegulatorService.sol';
/// @notice An ERC-20 token that has the ability to check for trade validity
contract RegulatedToken is DetailedERC20, MintableToken {
/**
* @notice R-Token decimals setting (used when constructing DetailedERC20)
*/
uint8 constant public RTOKEN_DECIMALS = 18;
/**
* @notice Triggered when regulator checks pass or fail
*/
event CheckStatus(uint8 reason, address indexed spender, address indexed from, address indexed to, uint256 value);
/**
* @notice Address of the ServiceRegistry that has the location of the
* RegulatorService contract responsible for checking trade
* permissions.
*/
ServiceRegistry public registry;
/**
* @notice Constructor
*
* @param _registry Address of ServiceRegistry contract
* @param _name Name of the token: See DetailedERC20
* @param _symbol Symbol of the token: See DetailedERC20
*/
function RegulatedToken(ServiceRegistry _registry, string _name, string _symbol) public
DetailedERC20(_name, _symbol, RTOKEN_DECIMALS)
{
require(_registry != address(0));
registry = _registry;
}
/**
* @notice ERC-20 overridden function that include logic to check for trade validity.
*
* @param _to The address of the receiver
* @param _value The number of tokens to transfer
*
* @return true if successful and false if unsuccessful
*/
function transfer(address _to, uint256 _value) public returns (bool) {
if (_check(msg.sender, _to, _value)) {
return super.transfer(_to, _value);
} else {
return false;
}
}
/**
* @notice ERC-20 overridden function that include logic to check for trade validity.
*
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _value The number of tokens to transfer
*
* @return true if successful and false if unsuccessful
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
if (_check(_from, _to, _value)) {
return super.transferFrom(_from, _to, _value);
} else {
return false;
}
}
/**
* @notice Performs the regulator check
*
* @dev This method raises a CheckStatus event indicating success or failure of the check
*
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _value The number of tokens to transfer
*
* @return true if the check was successful and false if unsuccessful
*/
function _check(address _from, address _to, uint256 _value) private returns (bool) {
var reason = _service().check(this, msg.sender, _from, _to, _value);
CheckStatus(reason, msg.sender, _from, _to, _value);
return reason == 0;
}
/**
* @notice Retreives the address of the RegulatorService that manages this token.
*
* @dev This function *MUST NOT* memoize the RegulatorService address. This would
* break the ability to upgrade the RegulatorService.
*
* @return The RegulatorService that manages this token.
*/
function _service() constant public returns (RegulatorService) {
return RegulatorService(registry.service());
}
}
Regulator Service
code: RegulatorService(javascript)
/**
Copyright (c) 2017 Harbor Platform, Inc.
Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.18;
/// @notice Standard interface for RegulatorServices
contract RegulatorService {
/*
* @notice This method *MUST* be called by RegulatedTokens during transfer() and transferFrom().
* The implementation *SHOULD* check whether or not a transfer can be approved.
*
* @dev This method *MAY* call back to the token contract specified by _token for
* more information needed to enforce trade approval.
*
* @param _token The address of the token to be transfered
* @param _spender The address of the spender of the token
* @param _from The address of the sender account
* @param _to The address of the receiver account
* @param _amount The quantity of the token to trade
*
* @return uint8 The reason code: 0 means success. Non-zero values are left to the implementation
* to assign meaning.
*/
function check(address _token, address _spender, address _from, address _to, uint256 _amount) public returns (uint8);
}
Service Registry
code:ServiceRegistry(javascript)
/**
Copyright (c) 2017 Harbor Platform, Inc.
Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.18;
import './RegulatorService.sol';
import 'zeppelin-solidity/contracts/ownership/Ownable.sol';
/// @notice A service that points to a RegulatorService
contract ServiceRegistry is Ownable {
address public service;
/**
* @notice Triggered when service address is replaced
*/
event ReplaceService(address oldService, address newService);
/**
* @dev Validate contract address
*
* @param _addr The address of a smart contract
*/
modifier withContract(address _addr) {
uint length;
assembly { length := extcodesize(_addr) }
require(length > 0);
_;
}
/**
* @notice Constructor
*
* @param _service The address of the RegulatorService
*
*/
function ServiceRegistry(address _service) public {
service = _service;
}
/**
* @notice Replaces the address pointer to the RegulatorService
*
* @dev This method is only callable by the contract's owner
*
* @param _service The address of the new RegulatorService
*/
function replaceService(address _service) onlyOwner withContract(_service) public {
address oldService = service;
service = _service;
ReplaceService(oldService, service);
}
}
Source