May 20, 2019
We will now take a closer look at Securitize’s newly released Digital Securities Protocol (DS Protocol).
In this post we will focus on two main elements:
The DSServiceConsumerInterface is a Solidity interface that all DS Protocol components implement, allowing them to associate with each other dynamically.
The interface’s main content is covered in these two methods:
function getDSService(uint serviceId) public view returns (address);function setDSService(uint serviceId, address _address) public /*onlyMaster*/ returns (bool);
It includes two functions:
setDSServicemethod we associate a Trust Service, Registry Service, and Compliance Service to a DS Token when it is created. This way the Token will know which specific smart contracts are responsible for each of those functions. In addition, because this method can be called again during the token lifecycle, it allows for future-proofing of the DS Token. For example, it’s now possible to upgrade the Compliance Service when a new regulatory requirement creates such a need.
getDSServicemethod allows enquiring a given DS Protocol smart contract about the other components it works in conjunction with. This allows asking a DS Token about the addresses for its Compliance Service or Registry Service. This is particularly relevant considering potential updates of DS Services during the DS Token lifecycle, as this will allow different actors to identify those changes and target the new components when necessary. For example (following the previous example of a Compliance Service upgrade) an exchange listing a DS Token would be able to identify the new Compliance Service and use its
preTransferCheckmechanism (we will cover this in a future post) simply by asking the DS Token about its address.
The potential components are identified by their
_serviceId which can have any of the values defined in
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;
The basic interface for the DS Token is defined in DSTokenInterface. This interface is an extension of the ERC20 standard, which means that all its methods (
totalSupply(), balanceOf(), allowance(), transfer(),approve(), transferFrom()...) are available and functional. This also means that any standard Ethereum wallet, like MyEtherWallet, MetaMask, or Coinbase Wallet, can hold and manage DS Tokens.
But the most interesting thing is that the DS Token also supports additional mechanisms relevant to Digital Securities.
Let’s look at them:
To ensure that DS Tokens transfers are kept within regulatory and issuer constraints, the
transferFrom() functions are adapted to rely on the controls provided by the Compliance Service. But besides that, an additional method is exposed by the DSTokenInterface:
function preTransferCheck(address from, address to, uint _value) view public returns (uint code, string reason);
This function calls the equivalent method exposed by the Compliance Service and allows checking whether a transaction will be allowed by it before actually executing it.
The implications of this new method and the
transferFrom() behavior will be analyzed in detail in our post discussing the Compliance Service.
The DS Token interface allows for multiple ways to issue tokens. They are defined by these three methods:
function issueTokens(address to, uint256 value) /*onlyIssuerOrAbove*/ public returns (bool);function issueTokensWithLocking(address to, uint256 value, uint256 valueLocked, string reason, uint64 _releaseTime) /*onlyIssuerOrAbove*/ public returns (bool);function totalIssued() public view returns (uint);
The first two simply allow the minting of new tokens and assigns them to a wallet, but with a relevant constraint: the DS Token will check with its assigned Compliance Service to ensure the destination wallet belongs to an investor that is allowed to receive such tokens. We will look at this also when we discuss the Compliance Service.
issueTokensWithLocking() allows issuing some tokens that have issuer-specific time constraints on trading. This can be relevant, for instance, when tokens have a certain vesting period associated.
totalIssued() method allows checking of the numbers of tokens actually issued up to the current moment, which will be always less than or equal to the standard
totalSupply() from ERC20.
DS Tokens also support iteration over all wallets holding tokens via the following methods:
function getWalletAt(uint256 _index) public view returns (address);function walletCount() public view returns (uint256);
This is particularly relevant when a smart contract (which in this case would act as a DS App) needs to interface with the token going across all its owners. An example of such a situation is when a DS App wants to provide some distribution mechanism, like dividends.
This is also a key improvement in DS Tokens from the ERC20 standard. In ERC20, the basic owner of a token is a wallet, but when we are discussing Digital Securities we need to consider regulations that are not concerned with “wallets” but rather, “investors.”
There are regulations that limit the number of investors an issuer can have depending on the filed exemptions and jurisdictions, which the DS Protocol must enforce. When an investor decides to keep their tokens in multiple wallets this can create a regulatory constraint for issuers. For example, an investor may keep most of their tokens on a hardware wallet while keeping the rest in a MetaMask wallet that they use to trade in a Distributed Exchange. By being able to attribute all of the tokens to the same investor rather than the multiple wallets, the tokens are maintained within the regulatory constraints without burdening issuers or limiting the ability of investors to utilize several wallets to hold their tokens.
The methods to manage DS Tokens in an investor-centric manner are presented here:
function balanceOfInvestor(string id) view public returns (uint256);function updateInvestorBalance(address wallet, uint value, bool increase) internal returns (bool);
Finally, some additional mechanisms are offered to the issuer with these methods:
function burn(address who, uint256 value, string reason) /*onlyIssuerOrAbove*/ public;function seize(address from, address to, uint256 value, string _reason) /*onlyIssuerOrAbove*/ public;function isPaused() view public returns (bool);
burn()allows issuers to destroy tokens, for instance in the case of a buy-back from investors.
seize()provides the issuer with the mechanism to seize tokens in case of a regulatory requirement to do this — for instance, in the case of token reissuance for an investor that has lost access to their tokens.
isPaused()is a complement to DS Tokens supporting the Pausable interface, that allows issuers to freeze token transfers. Being able to understand if the token is paused is relevant for the Compliance Service as well, so this method allows other DS Services to get this information from the DS Token.