TokenD is a multifunctional white label platform that consolidates the experience gained by Distributed Lab in building the production-ready tokenization solutions. It allows you to issue, transfer, and exchange your assets with high level of privacy, security, and auditability while following regulations of your jurisdiction. TokenD is designed for building tokenization solutions which you fully own and can customize; using its ready-to-use toolkit, one can release their blockchain product in a short time to market and without having to maintain the team of blockchain developers.
In the following video you can see sub-set of features supported by TokenD applied to the tokenized tickets use-case.
TokenD is designed for entrepreneurs and enterprises willing to take advantage of tokenization or experiment with the blockchain technology. TokenD can be used to build your own tailored next-generation accounting system: flexible, secure, auditable, and adaptive in terms of legislation.
Flexibility lies in the separation of processes in accounting: identity management, wallet management, asset transfer and exchange, role management, token lifecycle management, and deposit/withdraw. All these processes are performed by independent modules and can be customized through adjustable template smart contracts that the platform supports. Combination of these approaches allows for an easy integration with existing legacy systems.
User secret data never touch the servers. The system allows for interaction in which users never transfer their secret data (e.g., password) to the server. This means that the compromise of this data during the network transfer—as well as through hacking the key server—is excluded. Therefore, the platform owner no longer has to consider risks related to storing the user secret data as well as spend time and resources on providing additional security.
Hacker compromise won’t corrupt the system state. The state of the ledger entirely depends on transactions performed. Since all transactions are initiated by the users themselves via cryptographic keys, a malicious party won’t be able to modify the shared ledger even having full access to one of the servers storing it.
Accounting system can be real-time audited by an independent party 24/7. In particular, an auditor can be given a node with blockchain synchronized in real time and automatically (using the dedicated software) verify the correctness of ongoing processes.
The system supports adaptive permission management, which relates to both users and admins. Access levels can be fully customized for each account according to factors you adjust (e.g., country, age, income, etc.). This allows adapting the system's business logic according to regulations of particular legislation.
Feature Set | R3 Corda | Hyperledger Fabric | Ethereum | TokenD |
---|---|---|---|---|
Consensus | RAFT | Kafka | pBFT | FBA |
Smart Contracts | ✔ | ✔ | ✔ | ✔ |
Private Transactions | ✔ | ✔ | ✔ | |
External System Integration toolkit |
✔ | |||
Web/iOS/Android Wallet | ✔ | ✔ | ||
Commercial-scale funds management kit |
✔ | |||
Role-based Access Control | ✔ | ✔ | ||
Vanilla Regulatory compliance framework |
✔ |
Quick way for running TokenD local development environment with Docker. For production deployment use this guide.
# drop any persistent state to make sure you are working with clean install
$ docker-compose down -v && docker-compose pull
# spin everything up
$ docker-compose up -d
# wait while environment initialization is complete
$ docker-compose logs -f initscripts
Now you should be able to access web client at http://localhost:8060 and admin dashboard at http://localhost:8070 default seed for login is SAMJKTZVW5UOHCDK5INYJNORF2HRKYI72M5XSZCBYAHQHR34FFR4Z6G4
These instructions are just a guideline for what you should generally do. You may modify provided docker-compose.yml
or configuration files in configs
directory to accommodate your needs.
If you need any help with TokenD or would like to suggest a feature, please reach us via https://tokend.atlassian.net/servicedesk/
TokenD is a highly modular system built using the microservices architecture. TokenD can be divided into two parts: DLT-based logic (node) responsible for the key functionalities such as tokens management and distribution, rights management, etc.; auxiliary modules, which interconnect DLT with external systems, store user data, etc. A detailed overview of these modules and their connections is specified in figure below.
Node is a key component of the platform. It processes transactions, manages history, and provides an easy to use API to access the blockchain data. It consists of two modules:
Core — a replicated state machine that maintains a local copy of cryptographic ledger and processes transactions against it in consensus with a set of peers. It implements the federated consensus protocol and is responsible for tokens accounting and roles management. Documentation for the API is available here.
Horizon is the client-facing REST API server. It acts as an interface between the core and applications that want to access the network. It allows submitting transactions to the network, checking the status of accounts, and viewing transaction history. Documentation is available here.
Identity Service is a GDPR compliant module which stores data collected during the KYC (know your customer) procedure. To access the data, a user or admin needs to provide the digital signature, which is verified against the most recent state of the ledger. Such an approach provides a high level of security. This module also stores client-side-encrypted private keys of users. This prevents a malicious actor from getting access to the accounts of the system even having a full access to the storage. Documentation for this module is available here.
Web, iOS, Android wallets are client facing applications that
provide a wide range of functionalities: from storage of encrypted private
keys on the device, to token transfers, withdrawals, and trading. They
interact with the core of the system directly through the Horizon module and
signs all transactions and requests locally. Such an approach ensures that
users’ private keys are safe even in case of MITM (man in the middle) attacks.
Auxiliary modules connect blockchain with real world. Different modules are responsible for different processes: external integrations, payment system, exchange, identity verification, etc.
Modules communicate with nodes via API. Such a separation of accounting by the processes performed allows for easy integration with existing — even legacy-systems. Each module can be configured, replaced, and enhanced according to particular business requirements.
[PSIM] (Payment Services Integration Module) is a set of modules that play the role of a bridge between TokenD public blockchains, banks, payment gateways, exchanges. They reflect corresponding operations like deposit, withdrawal and exchange rate changes in another system.
ESIM (External System Integration Module) is a set of modules that interconnects TokenD with various external systems. They are responsible for a wide range of functionalities: from transfer notifications to automatization of the user identity verification.
Accounts are the central data structure in TokenD. Each account has:
All accounts are identified by a public key and, basically, are a piece of data stored on the ledger. All other data on the ledger, such as assets, offers, or KYC data, are associated with accounts.
The weight of a key determines its level of access for initiating a specific operation. Weight is needed to define the threshold for an operation to be performed.
To perform operations, for all accounts there is a set of permissions. Permissions are configured by administrators and can be customized for each individual account (this also relates to administrators who should have appropriate permission to configure the permissions of other accounts).
All accounts in TokenD can be split into two types: admin and user. Admins make decisions on configuring the system and setting business rules as well as verify users and grant them rights (permissions) to perform certain activity on the platform.
Users take advantage of the system functionality by performing operations—which they have permission to perform.
Each operation in the system (e.g., send a payment, manage orders, change account settings, etc.) is represented by a transaction. Moreover, one transaction may contain up to 100 operations. The result of each transaction is the modification of the TokenD ledger state.
Transactions are atomic, meaning that if there are multiple operations in one transaction, either all operations are performed successfully or none is. Thus, if one operation from the list fails, an entire transaction fails as well.
Each operation:
Keys. Each operation is signed by keys. Only the keys owner is able to perform operations associated with their account.
Permission. An account should have appropriate permission to perform a particular operation.
Threshold. Weight threshold is the signer’s access level, meaning that in order to perform a particular operation, a signer or group of signers should have the total weight equal or higher than the operation threshold. This is implemented via the multisignature mechanism.
Like any other system, TokenD requires users to register and authorize. The crucial difference, however, lies in the following aspects:
For a user, the registration in TokenD is not much different from that on any regular website, social media (e.g., Facebook), online shopping services (e.g., Amazon), etc.
While a user is only asked to perform simple and common actions, the under-the-hood of registration is entirely different. In simple terms, the user password is used to encrypt the user’s wallet before sending it to the server as well as to derive data by which a user will later authenticate to later obtain their encrypted wallet.
Since the function used for derivation is one-way, neither the server nor the man-in-the-middle can use authentication data to restore the user password.
The user password is the most crucial data which is needed to derive (generate) an encryption key. Losing or forgetting a password leaves the user without access to their keys. In such a case, there is a password change procedure.
Since the server never knows the user’s password, the password recovery procedure is radically different from traditional systems, yet possible. A user needs to enter the recovery seed (which had been previously shown to him/her during the registration) and a new password. The password will be recovered and new seed created (do not forget to save the new seed!).
Note: recovery seed is your cornerstone; if the password and recovery seed are lost, then the access to an account (as well as to all funds associated with this account) will be lost as well. No one except the user knows this seed, and it is shown ONLY ONCE, during the registration.
After a user has entered the seed into their application, a new wallet for him/her is created. This means that:
The Know Your Customer (KYC) solution needed for a specific case varies greatly on a number of factors such as the business requirements, budget, field of implementation, etc.
For this reason, instead of providing a ready-made, out-of-the-box solution, TokenD offers a toolkit for configuring your own as well as for integrating with third-party verification services.
As has been mentioned, TokenD doesn’t limit you in the number and type of user access levels as well as what data should be provided and for what access level. The KYC flow is fully customizable. You configure:
Note: the user access level can also be dropped at any time; to do this, an admin must be granted with a corresponding right.
An outsourcing solution is beneficial when you need to delegate the hardships of verifying the user KYC data.
For example, companies that build online trading platforms in the USA are strictly obliged to limit the investment choices of unaccredited investors. In such a case, the identification of whether an individual is accredited or not can be outsourced to corresponding services (e.g., IdentityMind)
Note: the development of external integration module and user access levels configuration takes approximately two weeks.
It is possible to define how specifically a user will be verified depending on the data provided, and thus implement multilevel, several-step identification. This is most beneficial in terms of various regulatory requirements.
For example. All users are verified manually by the platform admins, except for those from the USA, who need to prove they are accredited. In such a case, you can configure that if a user has filled the country box as “USA”, he/she will be automatically redirected (via API) to an outsourcing service that will proceed with identification.
TokenD team has already implemented some basic KYC flows. It is possible for user to be verified as a General, U.S. verified and U.S. accredited investor. Web application will authomatically define the verification flow depending on user's country and requested role will be visible for application reviewer. Thus, US residents, that are not able to prove their accreditation status won't have the ability to hold and invest to security assets.
TokenD provides an open-source reference implemenation of automatic verification service, that is integrated with IdentityMind sandbox environment. When connected to the real Identity Mind environment, such service will automatically handle most KYC applications without any need of involving human resources.
The implementation of the service is available on Gitlab
TokenD limits management is not only about enabling/disabling particular actions for particular users. Rather, it allows admins to define limit ranges within which users perform activity on the platform.
Limits can be imposed on:
Operation limits can be imposed on a type of account (e.g., unverified; verified; all users under 21 years old; all users without insurance documents; etc.) or a specific account.
Operation limits can be imposed on a particular asset type (e.g., to avoid speculation, one account cannot buy more than 5 tickets on one concert/show/etc.).
Operation limits can be imposed on specific time bounds (e.g., users from other than gold miner countries will not be able to buy more than 100g per day).
In TokenD, any account with corresponding permission can issue their tokens. Since there are two basic types of accounts (user and admin) tokens can also be nominally split into two types:
The only distinction between these two lies in the access level: users requests on token creation, pre-issuance, etc. are to be approved by admins. While an admin, if has the corresponding permission, manages a token throughout its lifecycle directly.
Token lifecycle consists of following steps:
At this stage, a token cannot be traded or transferred because it doesn’t actually exist. This is simply an announcement of token details: name, max issuance amount, permissions required to interact with this token.
After the pre-issuance stage, actual tokens already exist, but no one yet owns them—they are all locked up on a smart contract. Pre-issuance is either done automatically or manually.
Automatic pre-issuance means that a certain number of tokens, which were specified during the token creation, will be pre-issued immediately after one of the admins approves the token creation request.
Manual pre-issuance means that a user creates a pre-issuance file via an offline application, uploads it on the platform and waits for an admin approval (more detail in offline application).
Offline application is an instrument which allows increasing the level of security during the token pre-issuance as well as provides for the diversification of risks.
In a direct sense, an offline application is a separate software you download to your device to perform operations related to the token pre-issuance. It is available for both users and admins.
Using an offline application, token pre-issuance can be split into two stages both performed by different parties: one uses an offline application to generate the pre-issuance file and sign it with their keys, another uploads this file to the platform so that actual tokens are pre-issued. In this way, the risk of unauthorized token issuance on the platform is diversified due to the correct allocation of duties.
Offline application includes the following functionality:
Pre-issue tokens. This process means that a user/admin creates a pre-issuance file, where they specify the pre-issuance details (which token, how much to pre-issue). This file contains a transaction for pre-issuance, which, before being sent, has to be signed by the creator of the file and also by another party that uploads this file to the platform (these actually could be one person, but to increase the security and diversify the risks, it is recommended to allocate the pre-issuance process into two stages).
Change asset issuer. One example when this might be needed is when one of the parties responsible for pre-issuance had been fired from your organization, and you have to make sure that their key can no longer be used for signing the transaction for pre-issuance.
Generate a new key pair. For higher security, it is assumed that the keys that will be later used for the tokens pre-issuance are generated in an offline application. This is done to have higher confidence that they haven’t been exposed by hackers during the generation.
Offline issuance application, which allows you to securely create new preissuanceAssetSigner
and pre authorize tokens to be issued, is available here:
At this stage, tokens are put into circulation. This process can be performed either by direct issuance (manually or through PSIM) or through crowdinvesting.
Direct issuance presumes the manual transfer of tokens to user balances.
Crowdinvesting campaign can be created by any user with corresponding permission and should be approved by an admin (only the token creator is able to put their token up for sale on a campaign; for more details, see crowdinvesting campaigns).
Guide on integration with external fiat system is available here.
Unlike traditional order execution model—where users send requests to the main server to transfer funds—TokenD supports direct transfers between users. In particular, all transactions are initiated by the users themselves, through cryptographic keys.
Note: for a token to be transferred, both the sender and receiver need to have corresponding permissions. Otherwise, the system will return error, and the transaction won’t be submitted.
The FBA consensus implemented in TokenD allows achieving full finality of transactions. This means that a transaction is irreversible: once it has taken place on a blockchain (i.e., was accepted by validators), it cannot later be canceled.
TokenD supports an internal exchange module that allows users to exchange tokens issued on the platform without the need for integrating with external exchange services.
Note: which of assets can be traded on the exchange is defined by the platform admins. For this, an admin should create an asset pair and specify it as tradable.
Token redemption is the process of taking the corresponding amount of tokens out of circulation. One example of token redemption is during the withdraw process. Guide for withdrawal process in TokenD system integrated with Bank is available here
TokenD comes with a crowdinvesting marketplace solution that is implemented through smart contracts, which are performed directly on a blockchain. This allows for the following benefits:
To start their own crowdinvesting campaign, a user should:
TokenD is provided with a flexible and feature-rich set of tools for fees management, which allows creating custom fees imposition rules by choosing and combining the following parameters and modes:
Also, it is possible to choose whether a fee is flat or percentage and define the range in which the imposition of particular fee-charging scenarios takes place. For example, you can specify that USD withdrawals in the range between $0 and $100 are imposed with a flat fee of $0.5, and above $100, a percentage fee of 2% is imposed.
TokenD doesn’t presume a complete suite of admins with standard rights, but it rather gives you a toolset for realizing your own platform management policy. It is possible to customize:
Most decentralized blockchain systems do not support the allocation of duties—users are mostly equal in their rights. This doesn’t work in the business sector, where you must have competent people each with their own tasks and responsibilities.
Being not just a system supporting accounts of different access levels, TokenD allows setting up your own hierarchy of permissions which is strictly controlled via cryptographic keys.
Each admin is given a key that allows performing only a strict set of operations which you entirely select (e.g., approve/reject KYC requests of users from Europe + impose fees;)
TokenD supports account weights. To perform an operation, an initiator should have both required permission and enough weight.
Moreover, an operation can also be initiated and fulfilled by multiple admins whose total weight matches the operation threshold. This mechanism allows distributing the authority over processes among a specific number of parties.
Therefore, you can diversify risks related to individual admin’s censorship by distributing responsibility among others and thus increase the objectiveness of decisions taken in the system.
The process of admin registration, unlike the user registration, is rather more earnest and implies greater responsibility. In particular, a party will be asked to go through the sign-up flow and thus get an account ID.
Using an external communication channel, a party should send their account ID to an existing admin (with the corresponding permission) who will subsequently add a new admin account.
Guides will mostly cover the logic of submitting transactions, so here are a few statements about transactions you may want to know before starting to work with TokenD SDK and TokenD API:
source
- the ID of the existing account in the TokenD systemed25519
keypairJavascript SDK exposes the ApiCaller
and Wallet
classes that will simplify the process of crafting/signing the
transactions.
Let's assume our user has the TokenD account with ID - GD2XNPQCN6A6IRWJDADOVAL4YMDPYB6VTQRIXW7MVQAHCNBMO46KBCIC
and one of it's signers has the secret seed - SBW7DY3ZEYGGWQJG7JOPYXDIQFZYAC4DKIO75VINZXPIWWIQIJDCDCMZ
.
It's important to know that the seed of the signer and the account ID MAY NOT correspond to one key pair -
the list of account signers can be changed, while any account ID is permanent.
To submit the transaction to the TokenD network, we should create an ApiCaller
instance and provide it a
Wallet
instance that we want to be used for signing transactions.
import { Wallet, ApiCaller } from '@tokend/js-sdk'
const wallet = new Wallet(
"", // email param, usually be ommited here
"SBW7DY3ZEYGGWQJG7JOPYXDIQFZYAC4DKIO75VINZXPIWWIQIJDCDCMZ", // the secret seed of the signer
"GD2XNPQCN6A6IRWJDADOVAL4YMDPYB6VTQRIXW7MVQAHCNBMO46KBCIC", // the ID of the account
)
const api = ApiCaller.getInstance('http://tokend-backend.com')
api.useWallet(wallet)
api.usePassphrase("Our network passphrase")
Now api
will automatically sign any transaction and set it's source from the Wallet
we've provided.
await api.postOperations(op1, op2, op3)
TokenD already has necessary notifications for email verification and 2FA. But you are free to add any new notifications for any system event.
To set custom notifications, you need:
Set following section in your_project.env.yaml
file.
notificationsender:
image: tokend/notification-sender-svc:0.1.0
signer: S...
defaultchannel: 'email' # 'device' | 'email'
database:
local: true # will create postgres container in cluster
# local: false # will use provided postgres_connection_url
# url: postgres_connection_url
migrationscount: 1 # Do not change this, please
mailgun:
key: "key-..." # your private mailgun key
publickey: "pubkey-..." # your public validation mailgun key
domain: "mg.awesome.com"
fromname: AwesomeProject
fromemail: noreply@awesome.com
s3:
url: "https://s3.amazonaws.com" # URL to your bucket (mind region)
bucket: awesome-bucket # Your bucket name
accesskey: ""
secretkey: ""
region: ""
usestaticcredentials: true # Do not change this, please
firebase:
projectid: ''
serviceaccountid: ''
# Please, insert here whole content of your firebase access json file
accessfile: ''
androidpackagename: ''
sentry:
disabled: true # Will not use sentry
# disabled: false
# dsn: ...
templates:
- name: withdraw-success # will be used to identify template
subject: Your withdrawal request has been processed
# file with exactly this name must be in your s3 bucket
email: withdraw-success.html # will be used to send in email body
push: withdraw-success.json # will be used to send push notifications
Then generate your_project.k8s.yaml
file using tokend-cli:
tokend-cli gen k8s -f your_project.env.yaml -o your_project.k8s.yaml
Upload templates themselves to s3 bucket (their file names must be the same as in config).
Now you are ready to deploy to your aws kubernetes cluster. Run kubectl apply -f your_project.k8s.yaml
and you are ready to go!
You can use any HTML code. If you want to set some values dynamically, you need to set placeholders for them in your template:
{{ .Name }}
You are free to choose the way you prefer to upload your templates, named as in the config, to the root of the bucket, you set in the config.
To listen any system change you can use transactions endpoint
After getting needed update, you can use notification service API to send notification.
With Coinpayments you can enable deposit and withdraw of cryptocurrencies for your TokenD system.
coinpayments
configuration section you must fill public_key
and private_key
attributes with the corresponding values of your Coinpayments API key created beforedeposit
, deposit-verify
and withdraw
, – you must specify signer
as a secret seed of your TokenD master account and source
as it's account IDIn Developer edition files to edit are
configs/coinpayments-deposit-verify.yaml
,configs/coinpayments-deposit.yaml
andconfigs/coinpayments-withdraw.yaml
Every coin must be represented as an asset in your system. Follow this guide to create one:
9223372036853
(maximum possible amount)9223372036853
(maximum possible amount)0
First of all, we need the accountID
to identify the account:
import { base } from '@tokend/js-sdk'
const keypair = base.Keypair.random()
const accountId = keypair.accountId()
Then we need to add the signer to our account. For simplicity, we'll use the keypair we've created as a first signer of the account.
const signerPublicKey = accountId
Hovewer, any keypair can be used, and even more, every account can have multiple signers.
After generating the account ID and the keypair of account's first signer, we can create the operation that can be submitted to the TokenD system:
const operation = base.CreateAccountBuilder.createAccount({
roleID: SOME_PREDEFINED_ACCOUNT_ROLE_ID,
destination: accountId,
signersData: {
roleID: SOME_PREDEFINED_SIGNER_ROLE_ID,
publicKey: signerPublicKey,
weight: 1000,
identity: 1,
details: {}
}
})
// The detailed description of fields is provided via js-doc in the sources.
await api.postOperations(operation)
Fiat deposit/withdrawals is one of the most important functionalities an asset management system should provide for. In this document, we will review how it works in TokenD.
In this guide, we consider an example of integrating with SafeCharge. However, this knowledge can be further used to integrate with any other similar systems and platforms.
As in any other system, in order to integrate TokenD with external payment systems (e.g., banks, payment gateways, other blockchains, etc.), a "bridge" module needs to be developed. Further in the text, we will appeal to it as PSIM (Payment Services Integration Module).
Requirements for the Deposit flow:
preissuanceAssetSigner
should be controlled by a trusted party (token issuer). In this example, USDT is an asset issued in TokenD, and USD is a collateral for this token.In the deposit flow, the role of PSIM is to monitor the state of an account in the external system as well as to perform the issuance of the corresponding amount of tokens to the corresponding user once a new incoming transfer takes place.
Withdrawal is the process of exchanging tokens issued in one system to the collateral controlled by another system.
To be able to create the Withdrawal Request
, a user must have a corresponding permission, and an asset must have AssetPolicy::WITHDRAWABLE
enabled. For more details, check Create Withdrawal Request Operation. In order to integrate TokenD with external payment systems (e.g., banks, payment gateways, other blockchains, etc.), a "bridge" module needs to be developed. Further in the text, we will appeal to it as PSIM (Payment Services Integration Module). Integration with payment systems that provides end-to-end IDs is trivial (integration module is able to specify a unique identifier of the transfer; if another transfer is sent with the same identifier, the request will be rejected). In this guide, we propose a solution for payment systems that does not provide such mechanics.
The asset issuance is performed to the specific balance, not the account. So, if we need to issue 5 example
assets (EXT) to the account with ID GBGEKARFDSXC6XJHTFPTKLONELARRWIHEVDR2TPBIPUAMFZCV5JLVBAA
, we
need to know the EXT
balance ID from this account:
const { data: account } = await api.get('/v3/accounts', {
include: ['balances', 'balances.state'],
})
const extBalanceId = account.balances.find(b => b.asset.code === 'EXT')
If such balance doesn't exist, we can create one with the help of ManageBalance
operation:
const operation = base.operation.ManageBalance({
destination: 'GBGEKARFDSXC6XJHTFPTKLONELARRWIHEVDR2TPBIPUAMFZCV5JLVBAA',
action: base.xdr.ManageBalanceAction.createUnique()
asset: 'EXT',
})
await api.postOperations(operation)
Now we have the balance exists and can issue EXT
asset.
The issuance itself is performed in 2 steps - requesting the issuance and approving the request
To create the issuance request, use the CreateIssuanceBuilder
exposed by SDK:
const operation = base.CreateIssuanceRequestBuilder.createIssuanceRequest({
asset: 'EXT',
amount: '100.000000',
receiver: 'BBKVOTHCUDI4X5MFYNQN7YEAJYY7OPS3HO7J3BBESPQCV23MXW7LLMKR',
reference: 'Some unique random string',
creatorDetails: {
foo: 'bar'
}
})
await api.postOperations(operation)
Before doing so, we can manage the key/value storage to define the tasks
should be set, once request is created.
const key = 'issuance_tasks:EXT' // or 'issuance_tasks:*' to spread the rule for every asset
const operation = base.ManageKeyValueBuilder.putKeyValue({
key,
value: 8,
})
Setting the value to 8 means that the request will be created with 8
pending tasks. 8
is a bitmask and every
approving review can remove any amount of bits. Once there is no pending tasks for the request, it becomes
approved. We can also make all the requests become automatically approved by setting the value to 0
.
To review the issuance request, use the ReviewRequestBuilder
exposed by SDK:
const requestId = 10
const { data: request } = await api.getWithSignature(`/v3/requests/${requestId}`)
const operation = base.ReviewRequestBuilder.reviewRequest({
requestID: requestId,
requestHash: request.hash,
requestType: request.xdrType.value,
action: xdr.ReviewRequestOpAction.approve().value
reason: '',
reviewDetails: {
tasksToAdd: 0,
tasksToRemove: 8, // depends on our configuration
},
})
await api.postOperations(operation)
The Know Your Customer (KYC) solution needed for a specific case varies greatly on a number of factors such as the business requirements, budget, field of implementation, etc.
For this reason, instead of providing a ready-made solution, TokenD offers a toolkit. This toolkit allows configuring your own identification solution as well as integrating with third-party services in case you need to delegate the process and only receive data based on which to configure custom user permissions.
TokenD presumes a separate module which is responsible for storing the KYC (know your customer) data, and it is called Identity Storage. Who has permission to operate with Identity Storage is specified via keys given to the system admins—-to prove their permission, an admin provides the corresponding signature.
In order to integrate TokenD with external RegTech compliance solutions (e.g., IdentityMind, IDnow, etc.), a "bridge" module needs to be developed. Further in the text, we will appeal to it as ESIM (External System Integration Module).
To upgrade their account (i.e., change its type to the one with higher access level), a user has to pass the KYC procedure.
TokenD doesn’t limit you in the number and type of user access levels as well as in what data should be provided and for which access level; it is all customizable.
The flow of how a client upgrades their account to a higher type is as follows:
KYC recovery allows recovering access to the user account even if they lost all keys. KYC recovery consists of two main steps.
The client fills out the registration form. The system sends an email with a verification code. After successful email verification, the system saves encrypted keys and sends InitiateKycRecoveryOperation. Initiate KYC recovery operation drops all existing user keys and adds a new key with a specific signer role. This role doesn't allow the user to access any data or send any ordinary transactions until the user proceeds with the second step.
A user sends a create KYC recovery request operation and provides his KYC data. Admin reviews this request and accepts it. After accepting the request, user signer role changes to default so they will be able to perform all actions allowed to their role.
Sending each operation can make one or more changes in current system state. Them are called LedgerEntryChanges.
LedgerEntryChange contains information about:
changed LedgerEntry type
change type
payload that describes change
Possible change types:
created
updated
removed
state
- LedgerEntry was used in operation, but no changes was added
You are able to get transactions and related ledger changes using transactions list endpoint
This is an experimental API. Experimental APIs may be changed or removed without notice.
Before creating the poll entry, you may want to configure the system to define what type of voters can participate in the poll. For doing so, you can map the
permissionType
of the poll with one or many account rules.
To create poll request, use the ManageCreatePollRequestBuilder
exposed by SDK:
Create poll request:
const SAMPLE_PERMISSION_TYPE = 4
const operation = base.ManageCreatePollRequestBuilder.createPollRequest({
permissionType: SAMPLE_PERMISSION_TYPE,
numberOfChoises: 2,
pollType: base.xdr.PollType.singleChoice().value,
creatorDetails: {
foo: 'bar'
},
endTime: 1553427080,
startTime: 1553254282,
voteConfirmationRequired: false,
resultProviderID: 'GDWYBLSZIXTTBGWRWBAYVFE6ZDL5GBS3ILOCLVXFB3NX4FFJJDGQUKLB',
allTasks: 1,
})
await api.postOperations(operation)
Detailed description of params is provided via js-doc in sources or in format of [XDR definitions][create-poll-request]
Until approved or permanently rejected, request can be cancelled by it's creator. To cancel the request, use
the same ManageCreatePollRequestBuilder
:
const operation = base.ManageCreatePollRequestBuilder.cancelPollRequest({
requestID: '10',
})
await api.postOperations(operation)
Detailed description of params is provided via js-doc in sources or in format of [XDR definitions][cancel-poll-request]
After request is created, it can be reviewed by admin using ReviewRequestBuilder
. For example, to approve
request, submit the following operation:
const requestId = 10
const { data: request } = await api.getWithSignature(`/v3/requests/${requestId}`)
const operation = base.ReviewRequestBuilder.reviewRequest({
requestID: requestId,
requestHash: request.hash,
requestType: request.xdrType.value,
action: xdr.ReviewRequestOpAction.approve().value
reason: '',
reviewDetails: {
tasksToAdd: 0,
tasksToRemove: 1, // depends on configuration, to fully approve request remove all pending tasks
},
})
await api.postOperations(operation)
Detailed description of params is provided via js-doc in sources or in format of [XDR definitions][review-request]
After following this steps, the poll should be created and ready to accept votes after startTime
.
After endTime
has passed any votes will be rejected,
and poll needs to be closed explicitly by providing voting result.
To resolve poll as passed, submit the following operation:
const pollId = 5
const operation = base.ManagePollBuilder.closePoll({
pollID: pollId,
result: base.xdr.PollResult.passed().value,
})
await api.postOperations(operation)
If poll has failed, submit the following operation:
const pollId = 5
const operation = base.ManagePollBuilder.closePoll({
pollID: pollId,
result: base.xdr.PollResult.failed().value,
})
await api.postOperations(operation)
Detailed description of params is provided via js-doc in sources or in format of [XDR definitions][manage-poll]
To submit the transaction to the TokenD network, we should create an ApiCaller instance and provide it a Wallet instance that we want to be used for signing transactions.:
import { Wallet, ApiCaller } from '@tokend/js-sdk'
const wallet = new Wallet(
"", // email param, usually be ommited here
"SBW7DY3ZEYGGWQJG7JOPYXDIQFZYAC4DKIO75VINZXPIWWIQIJDCDCMZ", // the secret seed of the signer
"GD2XNPQCN6A6IRWJDADOVAL4YMDPYB6VTQRIXW7MVQAHCNBMO46KBCIC", // the ID of the account
)
const api = ApiCaller.getInstance('http://tokend-backend.com')
api.useWallet(wallet)
api.usePassphrase("Our network passphrase")
Now api
will automatically sign any transaction and set it's source from the Wallet
we've provided.
await api.postOperations(op1, op2, op3)
After that we can create createSigner
operation:
const operation = base.ManageSignerBuilder.createSigner({
weight: 1000,
identity: 1,
publicKey: 'GDWYBLSZIXTTBGWRWBAYVFE6ZDL5GBS3ILOCLVXFB3NX4FFJJDGQUKLB', // the ID of the account
roleID: 1,
details: {
'foo': 'bar'
},
})
await api.postOperations(operation)
Detailed description of params is provided via js-doc in sources or in format of [XDR definitions][manage-signer]
You can check whether signer was created or not by getting list of account signers
const accountId = 'GD2XNPQCN6A6IRWJDADOVAL4YMDPYB6VTQRIXW7MVQAHCNBMO46KBCIC'
const { data: signers } = await api.getWithSignature(`/v3/accounts/${accountId}/signers`)
Detailed description of params is provided via js-doc in sources or in format of [horizon definitions][signers]
By using checkSignature()
, you can validate signature
const express = require('express')
const { ApiCaller } = require("@tokend/js-sdk")
const app = express()
const port = 3000
const tokenD = ApiCaller.getInstance("http://localhost:8000/_/api/")
const accountId = 'GD2XNPQCN6A6IRWJDADOVAL4YMDPYB6VTQRIXW7MVQAHCNBMO46KBCIC'
const checkSignature = (owner) => (req, res, next) => {
let payload = {
data: {
attributes: {
headers: {},
},
relationships: {
signer_of: [
{id: owner},
]
}
},
}
Object.keys(req.headers).map(function(key) {
payload.data.attributes.headers[key] = req.header(key)
})
payload.data.attributes.headers["(request-target)"] = `${req.method} ${req.path}`.toLowerCase()
tokenD.post("/integrations/doorman/validate", payload)
.then(_ => next())
.catch(e => {
const response = e.originalError.response
if (response.status >= 500) { // TokenD having a bad day
res.sendStatus(500)
}
if (response.status === 422) { // our request was invalid in some way
res.sendStatus(500)
}
// signature didn't pass validation
res.sendStatus(e.originalError.response.status)
})
}
app.get('/MyAwesomePath', (req, res) => {
checkSignature('GB74P7P5QNJFFDZSH4PRVSAJZYPMJQU4D4D355I3OG4WGDWSIN6YGK32')
res.sendStatus(200)
})
app.listen(port, () => console.log(`listening on port ${port}`))
This is an experimental API. Experimental APIs may be changed or removed without notice. If the poll is approved and started, accounts can start casting votes for the choices the poll suggests. To manage votes, SDK exposes
ManageVoteBuilder
for building operations.
To cast a vote in single-choice poll for the 10th option:
const operation = base.ManageVoteBuilder.createSingleChoiceVote({
pollID: '5',
choice: 10,
})
await api.postOperations(operation)
To cast a vote in multiple-choice poll:
const operation = base.ManageVoteBuilder.createMultipleVotes({
pollID: '6',
choices: [10,11,12],
})
await api.postOperations(operation)
Detailed description of params is provided via js-doc in sources or in format of XDR definitions
Votes can also be recalled. Same operation is used for both single and multi-choise polls:
const operation = base.ManageVoteBuilder.removeVote({
pollID: '5',
})
await api.postOperations(operation)
Detailed description of params is provided via js-doc in sources or in format of XDR definitions
Reviewable requests are operations that can be reviewed before changing ledger state. This requests can be reviewed by admin or any system module.
Reviewing process is managed by tasks. While reviewing or creating
requests you can set or remove tasks using fields
TasksToAdd
and TasksToRemove
. After processing review admin
or module should remove this task If there are no pending tasks
the request will be accepted.
Tasks are uint32
values that can be customized differently
for specific system. Task must be 2^n
. TokenD already has
some tasks defined for its integrations.
default = 1
- request needs review by admin.submit_auto_verification = 1024
- request needs review
by IDMind module.complete_auto_verification = 2048
- request waits for IDMind
verification completion.manual_review_required = 4096
- IDMind failed to check KYC
and it needs review by admin.TokenD 4.6 release is focused on adding the ability to use arbitrary data entries (called Data
) and the addition
of liquidity pools for decentralized exchanges based on Automated Market Makers (AMMs).
TokenD 4.6 have implemented a DEX based on the Uniswap v2 protocol to facilitate seamless trading and liquidity provision. It is possible to:
These new features aim to provide a more versatile and user-friendly trading experience.
Data
is a versatile ledger entry introduced in this release, which allows users to store, delete, update, and transfer
arbitrary data between owners. With the Data
feature, users can now implement a wide spectrum of use cases, such as:
This new functionality empowers users to create innovative solutions and enhances the overall utility of the TokenD platform.
TokenD 4.6 also includes several general improvements and bug fixes to ensure a smoother and more reliable user experience
Traefik is a new API gateway that is presented in the current release. It is more stable than Janus and replaces it. You may continue to use Janus as new Services are fully backward compatible with it. In case of migrating to Traefik use this guide.
A few new endpoints was added to horizon:
For details check horizon documentation
TokenD 4.4 release is focused on adding redemption functionality.
There are several circumstances in which an Investor is forced to transfer their assets to the another person after a specific event is triggered.
Some of these 'trigger events' can include:
For this redemption reviewable request was added. The asset owner can create a request for transferring funds of some holder to another person and add some documents or other details to this request. Admin will be able to review this request and approve it reject. Until review funds are locked, after review depends on result funds will be transferred or returned to holder.
TokenD 4.3 release is focused on adding the ability to integrate with ERC20 and Stellar tokens while creating a non-system asset
When creating a new non-system asset, the user can now set up a bridge to Ethereum (ERC20) or Stellar network for this asset.
Once bridges for Stellar and ERC20 assets are configured, platform users will be able to deposit and withdraw these assets.
Identity module is now able to store custom settings
Identity module will now store unverified wallets only for some period of time that can be set in configs:
wallets:
cleaner_period: 24h
This will help to protect from blocking an email address from registration on the platform by starting registration process for it.
TokenD 4.2 release is focused on adding new types of token sale campaings.
Up until version 4.2 TokenD employed a token sale mechanics where investors' funds were locked the assets were issued to participants' accounts upon the sale completion.
In the new type of sale assets are issued to the participants' accounts immediately upon investment in a sale.
TokenD 4.1 release is focused on improving the framework core. We have significantly re-worked our XDR library, did some source refactoring and performance improvements.
TokenD 4.0 release is focused on extending our framework with bridges to the Stellar as well as Ethereum network in the case of ERC20 tokens. We have also added the KYC Recovery flow to the reference implementations of web-client and admin-panel as well as introduced the Direct sales feature.
When creating a new system asset, the platform administrator can now set up a bridge to Ethereum (ERC20) or Stellar network for this asset.
Once bridges for Stellar and ERC20 assets are configured by the platform administrator, platform users will be able to deposit and withdraw these assets.
It is also possible to use TokenD 4.0 for the initial asset issuance and then withdraw those assets to either of the two networks.
We introduced the KYC Recovery feature on the back-end in TokenD 3.5.0. In TokenD 4.0, we have removed the account recovery with a seed feature because it was hard to understand for end-users. Instead, we are now using the KYC recovery flow in our reference implementations of web-client and admin-panel.
If platform users had passed the KYC procedure and then lost access to their account, they can make an account recovery request by re-submitting the KYC data and have their account unlocked upon review by the platform administrator.
Platform administrator compares the user's newly submitted KYC data with the existing and based on this, makes a decision to the restore the user account.
Direct sales feature allows selling the assets issued on the platform for assets without depositing it to the platform.
Such assets need to be marked accordingly by the platform administrator on the System assets management screen.
Once this is done, corporate users can now create assets eligible for direct sales.
We have added the purchase flow for direct sales to our reference implementation of mobile clients: android-client and ios-client.
![]() |
![]() |
---|
In future we may add the purchase flow to the web-client as well.
TokenD 3.6.0 release is focused on adding blockchain-backed voting functionality to the platform. A reference implementation of voting functionality has been added to web-client and admin-panel.
The reference implementation allows corporate users to create polls, while platform users who hold a specific asset can participate. The feature models a decision-making process between asset holders and asset issuer.
Similar to sales, polls are created by submitting a request to the platform administrator. Once the poll is approved, it becomes available in the Polls section.
Corporate users can now see the movements of their assets between asset holders in Register of shares section. It is now also possible to filter assets by their ownership via My assets in Assets section.
By default, polls are based on the general reviewable requests functionality so platform administrators have to approve a poll before it becomes available to the platform users. Functionality for browsing and approving poll requests have been added to the admin panel.
Package dependencies have been updated to eliminate some security issues caused by outdated packages.
The 3.5.0 release introduces a toolset for building the KYC Recovery flow to the TokenD core. Now if platform users forget their password and do not have the recovery seed, they can still regain access to their accounts via the KYC Recovery flow. With this flow implemented, users can send a request to the platform admin, submit their KYC documents to prove the account ownership and have their account unlocked by the platform admin.
The following documentation allows building your own KYC Recovery flow for your front-end application:
A reference implementation for TokenD default web-client and admin-panel is going to be added in the upcoming releases.
System-wide status massages design have been improved for more consistency.
We added a new "Cap asset" field to allow a user to choose the asset in which he/she can see the investments collected as a result of their crowdinvesting campaign. Under the hood, the balance for the asset which a user marked as "Accept investments in" is created , then the balance is converted according to the exchange rate with the "Cap asset", and the "Cap asset" balance is eventually shown.
Fees area in the "Send assets" form has been reworked for better readability. Fees calculation details are still available by the Show my account fees link.
Modern skeleton loading templates have been added to the web-client to improve application performance and overall user experience.
Collected fees management screen has been added to the Fees section of the admin-panel. Now platform admins can make withdrawal requests for fees collected from platform users.
Whitelist tab has been added to the Sale details screen, meaning that now platform admins can see users that are whitelisted for the sale participation. Also, Whitelisted property in the Sale details section indicates whether thea sale requires whitelisting or not.
Notes:
Pre-issuance Guide Page links has been added to Offline operations → Pre-issuance and Offline operations → Change asset issuer screens.
Limits management form improvements:
By following the links below, you may find the other changes:
The general verification form has obtained a set of new fields such as Country, Date of Birth, Address Details as well as the ability to upload different Identity Documents.
Because of special regulations for U.S. citizens that affect their ability to invest in security assets, we have added a new flow for U.S. accredited investors and improved our flow for the verification of general users. Now every user who has selected "USA" as their country of residence will be prompted to upload the proof that he/she is an accredited investor. If he/she uploads the proof, the role of their request will be automatically defined as "US Accredited". Otherwise, the role of the request will be "US Verified" and once it is approved, a user will not be able to hold assets of the type "security".
In addition to the internal KYC module, TokenD can be configured to work with third-party verification services. To provide an example of how this could be done, we have developed an IdentityMind integration module. We share this source code as a reference implementation, which you can further re-use by adding your IdentityMind credentials and configuring it to your KYC workflow. See this repository for details.
Charts have been improved. Now, they better re-render animation and have floating hints.
All email addresses can be easily copied via the copy button.
We have introducted the naming consistency: now all funds are called sales, and all tokens are called assets. On the admin-panel, we combined all the pages related assets into a single Assets menu item.
We introduced Block to allow admins to block particular users. Under the hood, this is a general Change role request operation, and it is being automatically approved. The action forces a user to acquire a blocked account role. The role has no actions allowed except for some basic ones such as log in, log out, etc.
Note: This is our default configuration of the blocked role. It can be configured in a different way but make sure you really understand what you do.
Admins can block a user by pressing the Block button on the User details screen (Users or KYC requests page >> Users list’s). Blocked users can be unblocked by pressing the Unblock button (depending on whether a user is blocked or unblocked, this button changes correspondingly). After unblocking, admin-panel restores the previous approved KYC request, so that all the previously approved KYC data is restored.
Web-client will show an appropriate account role under the user email in the top-right corner of the page. The blocked user can see the block reason on the Verification page, but there will be no KYC data displayed. By default, web-client does not hide any functionality for blocked users, but they will get an error if they try any restricted action.
We introduced Idle auto-logout to our web-client and admin-panel. Idle auto-logout default behavior
Note: Under the hood, the log out is being performed on the client’s side entirely. There is no server-side functionality supported for this yet, but we are actively researching to find the best approach to this feature. TokenD does not know users' or admins' keys because they are stored encrypted with the passwords of users or admins, and these keys cannot be decrypted by anyone else (in this instance, there is no "master-key" that rules over all other system keys).
Limit request details have been added to the Limits screen. Limit request details display request details, actual request state and the reject reason in case there is one.
The request list have been moved above the actual limits for easier accessibility.
We redesigned the status message: it has brighter colors, some animations and more verbose server-side error outputs.
For the following elements, the redesign work has been done:
offline-issuance-related operations have been moved to a new menu item, Offline operations.
[TDV-109] - [Auxiliary Modules] Сoinpayments integration module.
[TDV-171] - [Client] [Admin] Coinpayments UI integration.
In Admin, when an asset is created, check the Coinpayments checkbox. After this, in Client, Deposit and Withdraw sections will have Coinpayments option available for according assets. By default, TokenD is configured to use a DL Coinpayments account.
If you are using Coinpayments for anything other then LTCT (Litecoin testnet), please re-configure it to your Coinpayments account. To setup your Coinpayments account in TokenD, see the corresponding section in this doc.
[TDV-3] - [Auxiliary Modules] Service for the request signature verification.
[TDV-5] - [Core] Ledger changes filter for transactions.
[TDV-356] - [Android] Asset pairs list screen.
[TDV-362] - [Android] Trade history.