Project Overview
This is a working document and changes are expected. Currently as of Nov 2024, pages with * prefix are yet to be updated to the new design with SPV legal structure.
NYMLAB is building the Platform-D project, which is comprised of components and integration between different legal entities.
The project's core utility is for SME owners to securitise and tokenise their electronic invoices efficiently; for buyers, a way to demonstrate good payment history and access better suppliers and rates; for investors, a way to democratise credit transmission investments.
The investment grade security-tokens provide low risk, deposit-rate-plus yield for retail & institutional investors.
In order to achieve this, there are 3 core entities with specific functions.
- Digital SPV: PD-SPV - A digital (both on and off chain) special purpose vehicle that issues security tokens backed by electronic invoices and artifact that make up Origination Data Package (ODP).
- Digital Securities Depository (DSD): Platform-D Ltd A regulated entity that provides the infrastructure for the issuance and settlment of securities, in this case, recorded as tokens on a Blockchain.
- Assurance Reserve Trust (ART): PD-ART A trust that holds fiat currency reserve offchain for PTs issued by the SPV.
The onchain parts of all the components are built on D-Chain. For details on the chain, please refer to the D-Foundation documentation.
In the initial MVP stage, Platform-D Ltd will only operate the DSD. It is however planned for it to also operate as an MTF.
We will highlight the key technical components here, for more details, please refer to the legal structures documents.
| Roles / License | Entity | Description and Component interactions |
|---|---|---|
| DSD & MTF | Platform-D Ltd. | Issuance and settlement of PTs - smart contracts and registered on x/orderbook, x/tokenfactory |
| SPV | PD-SPV Ltd. | Notarises ODP, PT price discovery and services PTs - build on smart contracts and registered x/notary, x/orderbook, x/tokenfactory |
| Verifiable Credential Issuer & Custodian | Gayadeed (for PD-SPV) | Document composition, digital signature, issuance and storage of verifiable credentials |
| Onboarding services (KYC / KYB / AML) | Gayadeed (for PD-SPV) | The KYC / AML flow for onboarding is provided by Gayadeed |
| Crypto AML / tx services | Gayadeed (for PD-SPV) | transaction APIs: enforce checks via webauthn |
Repos overview
| Repo | Description | Specs |
|---|---|---|
| Chain | D Chain modules and contracts | Docs |
| SPV Webapp | This needs to be forked / replaced to here | |
| SPV contracts | Smart contracts for SPV | see SPV onchain services |
| DSD contracts | Smart contracts for DSD | see DSD onchain services |
| SPV APIs | Backend API for the webapp | |
| Gayadeed VC API | Issuer and custodian of verifiable credentials | |
| Gayadeed Onboarding API | KYC / AML onboarding flow pre-account registration | |
| Utils: Protobuf rust & grpc clients | Rust protobuf get and GRPC tonic clients | |
| Utils: Protobuf ts & codegen clients | TS protobuf interfaces and contract interfaces |
MVP stack

Contribution Guide
This book is a series of markdown files, please see general style guide.
Easy version control
In order to easily identity git diffs, make sure to break up sentences / paragraphs to different lines logically (Typically at comma / full stops etc).
**DO NOT DO THIS**
This is a long sentence, with comma and others. Changing a single word will cause a diff on a whole paragraph.
**DO THIS INSTEAD**
This is a long sentence,
with comma and others.
Changing a single word will only cause a diff on a single line.
Reference links
For reability and not to repeat oneself, we please look at the following for how to do hyperlinks in a page
This is a page with some links:
--------------
**DO NOT DO THIS**
- [google](https://google.com) can be used to search the internet, by using [google](https://google.com)...
--------------
--------------
**DO THIS INSTEAD**
- [google] can be used to search the internet, by using [google]...
Then at the bottom of the page you can link references
[google]: https://google.com
--------------
Frontend Only Demo
This project is for a sprint that will demonstrate visually only E2E from an invoice (existing) and added already to platformD to the point where the PT securities are created.
Highlevel components required in this demo:
- platformD WebApp
- Supplier
- Investor
- platformD server
- CRUD states (Invoices, PTs, Users) (mock chain states)
- orderbook
- Gayadeed
- SPV tenant
- VC-API
The flow can be seen in this:
sequenceDiagram autonumber actor s as Supplier actor o as Obligor participant ws as WebApp <br /> Supplier participant spv as SPV <br /> backend participant g as Gayadeed participant wi as WebApp <br /> Investor actor i as Investor s ->> ws: Log In note over ws: 1. Get Invoices s->> ws: Selects Invoice <br /> Request for CTA ws ->> spv: request create deed spv ->> g: deeds/create g ->> o: invites to sign note over g: VC issued g ->> spv: Sends VC note over spv: invoice status: Notarised s ->> ws: List Invoice <br /> w/ reserve price ws ->> spv: updateInvoice <br /> status: listed note over spv: Create sell order in orderbook i ->> wi: Buy order wi ->> spv: Create buy order in orderbook note over spv: Order matches note over spv: 1. deduct investor account note over spv: 2. credit supplier note over spv: 3. create PTs note over spv: 4. update invoice: status sold
Objects Design
User
Data Structure
- userid
- role (supplier, investor)
- balance (Euros)
- supplier VAT (if supplier)
Invoice
States
stateDiagram-v2
[*] --> Pending_CTA
Pending_CTA --> Notarised
Notarised --> Listed
Listed --> Notarised
Listed --> Settled
Template of Verifiable credential for invoice
disclosable: disclosable in sd-jwt
- supplier VAT
- buyer name
- supplier name
- invoice number (specific to the invoice)
- creation date (ddmmyyyy)
- (disclosed) buyer VAT
- (disclosed) supplier_onchain_address dchain addr
- (disclosed) reference to calculate the DID of the notorised asset
- (disclosed) DID (identifier of the notarised asset - did:dchain)
- (disclosed) total_amount_due : coin (amount, denom)
- (disclosed) payment_due_date: timestamp
Reference string for notarise asset is hash of:
- buyer VAT
- supplier VAT
- invoice number
- invoice issuance date (ddmmyyyy)
- amount due
PT
There are 2 underlying structure here
- PT (the actual structure representing the security with the metadata)
- PT units (the units related to one of the PT structures)
PT Data Structure
- ISIN;
- Status: (Issued, Matured, Redeemed)
- ref_id (key for PT Units)
- Max supply
PT Units
in the db it will just be key (ref_id, user_id)
- ref_id
- owner (userid)
- amount
Order
Data Structure
- type: buy / sell
- reserver price
- quantity
- filled (sell only will this be 0 / 100%)
Orderbook
AON - All or nothing on the sell side orderbook
Gayadeed Deed creation
{
"folderName": "BUYEXXYZ",
"folderType": "PLATFORM_D_CONTRACT",
"kind": "INVOICE_NOTARIZATION",
"signType": "FEQ",
"enableChecklist": true,
"signatoryUserId": <ENV_TENANT_USER_ID>,
"description": "202510123",
"participants": [
{
"name": "Egidio",
"surname": "Casati",
"email": "egidio.casati+odp_01@gmail.com",
"phoneNumber": "+39-3459277339",
"fiscalCode": "CSTGDE70C22F205C",
"gender": "M",
"birthDay": "1970-03-22",
"cityBirthPlace": "Milano",
"districtBirthPlace": "MI",
"birthCountry": "IT",
"citizenship": "IT",
"address": {
"street": "Viale Teodorico",
"number": "7",
"city": "Milano",
"district": "MI",
"cap": "20149",
"region": "Lombardia",
"country": "IT"
},
"metadata": {
"BuyerName": "ACME S.p.A",
"BuyerVatNumber": "IT12312312312",
"BuyerAddressStreet": "C.so di P.ta Vittoria, 47",
"BuyerAddressCity": "Milano",
"BuyerAddressZipCode": "20122",
"BuyerAddressCountry": "Italy",
"BuyerLegalRepName": "Egidio Casati",
"BuyerLegalRepTin": "CSTGDE70C22F205C",
"SupplierName": "NYMLAB Srl",
"SupplierVatNumber": "IT32132132132",
"SupplierAddressStreet": "piazza del duomo, 1",
"SupplierAddressCity": "Milano",
"SupplierAddressZipCode": "20100",
"SupplierAddressCountry": "Italy",
"SupplierOnchainAddress": "dchain:0x1234567890abcdef1234567890abcdef12345678",
"OnchainRef": "some-hash-of-the-invoice-data",
"DID": "did:dchain:1234567890abcdef1234567890abcdef12345678",
"InvoiceId": "2025010123",
"InvoiceIssueDate": "2025-06-15",
"InvoiceAmount": "25000.00",
"InvoiceDescription": "Consultancy Q1 2025",
"InvoicePaymentDueDate": "2025-07-15",
"InvoiceUpdatedPaymentDueDate": "2025-07-31"
},
"participantType": "SUBSCRIBER",
"personType": "NATURAL_PERSON"
}
],
"autoStartConfig": {
"afterDocumentAutoGeneration": false,
"afterChecklistCompletion": true
}
}
Digital SPV (PD-SPV)
platformD Web Applications
There are several individual applications:
- Public Website (Details / Docs / Background / Call to action)
- Public Analytics Dashboard: Current platformD statistics including the art (differ from Dchain dashboard)
- Authenticated Page is the majority of the applications
We will focus on the Authenticated Area in this section.
Authenticated Page
Important to note that the authenticated area itself is a wallet using the Vectis infrastructure
This page contains:
- Account Info (Personal data / documents uploaded)
- Verifiable credentials (stored (custody) in Gayadeed servers)
- Physical Person
- Eligibility to use Platform-D
- Notarised invoices (Suppliers)
- Legal Person (Suppliers)
- potentially others...
- Wallet settings: Plugins etc (see old demo
- Balances and User transactions (see previous dashboard)
- Orderbook
- Suppliers notarisation workflow tab (Unlocked by completing more checks)
- Investors investment tabs (Unlocked by completing more checks)
Gayadeed API and Integration
This service serves as the middle point between Gayadeed other services and [Platform-D API]. In general, it provides offchain processes, data and information, e.g.
- KYC / AML process
- Personal data storage (uploaded documents)
- Issuance of verifiable credential process
- Verifiable Credential storage
- Provides the challenge for webauthn and verify
platformD API
This service is the main backend of the UI. As accounts authenticate into Gayadeed API, they are automatically authenticated into this service.
Most onchain services are provided here:
- Crypto continuous AML
- Indexing onchain transactions
- Provide pricing data onchain
Onboarding
The onboarding of all users require a minimal KYC requirements no matter what role they undertake.
The key identifier for any users in the system is their credential in Keycloak,
the subject sub identifier is used across all microservices.
Components involved in the onboarding process are:
- Keycloak v24 instants (Platform-D Realm): Supported by Postgres integration
- [
User Management] : Rust based, holds Keycloack Admin Client Connections, used for user registration Gayadeed KYX: Golang based, interacts with SPID, Sefin, Jumio and ComplyAdvantage, used for KYC and blacklist checkGayadeed VC-API: Golang based, interacts with Paradym, used for issuance and storage of batch verifiable credential- [
Account]: Rust based, interacts with D-Chain, used for creating onchain wallet and updating user wallet address
Apart from the Keycloak Admin Client connection, all services communicate via gRPC.
Sequence of onboarding and logging in
sequenceDiagram
autonumber
actor User
participant Keycloak
participant User Mgmt
participant Gaya-kyx-&-vc
participant D-Account
participant D-Chain
Keycloak --> User Mgmt: Holds Admin Client <br> controls user attributes
User ->> Keycloak: Create Webauthn Credential
User ->> Keycloak: Login with token
User ->> D-Account: check `AccountKycStatus`
alt AccountKycStatus == `init`
D-Account->> Gaya-kyx-&-vc: `GayaKyxCreateTransactionService` <br> with `response_endpoint` to User Mgmt
Gaya-kyx-&-vc ->> D-Account: `CreateTransactionResponse` with `challenge_url`
Note over D-Account, Gaya-kyx-&-vc: The `response_endpoint` is in the transaction request <br> but challenge_url is returned to D-Account for the User
D-Account ->> User: re-route to `challenge_url`
User ->> User: Jumio web client re-route to <br> `platformd.io/kyx-pending`
Note over Gaya-kyx-&-vc: Jumio calls `/kyx/callback` on update
Gaya-kyx-&-vc ->> User Mgmt: `GayaKyxCallbackService` <br> with status and decide if it should issue credential
User Mgmt ->> Gaya-kyx-&-vc: `CallbackResponse` <br> with info regarding if Gaya-vc should be called
opt On `CallbackResponse` create physical person cred == true
Gaya-kyx-&-vc ->> Gaya-kyx-&-vc: Request batch issuance of credential for physical person
end
User Mgmt ->> Keycloak: Update user attributes accordingly
else AccountKycStatus == `pending`
D-Account ->> User: wait
else AccountKycStatus == `success`
Note over D-Account: Check `token.dChainAddr`
alt token.dChainAddr == empty
D-Account ->> D-Chain: create onchain wallet
D-Account ->> User Mgmt: update token.dChainAddr field
else token.dChainAddr == not empty (support only 1 in this case)
D-Account ->> D-Chain: query data (also from indexer)
D-Chain ->> D-Account: return account data
end
D-Account ->> User: Return account data
end
User registration
Impl: Keycloak Platform-D Realm
This step users interact with keycloak Platform-D realm to register their Webauthn credentials. The public key created and stored in keycloak will be used to create they Onchain wallet later on.
The tokens must present following attributes on top of the standard OIDC claims:
{
"kycStatus": "init",
"roles": ["<roles>"]
"dChainAddr": ["<address>"]
}
-
kycStatusincludes both identity proofing and blacklist check status. Please see KYC Status for more details. This attribute is updated by thegaya/kyxcalling to the UserManagement API. -
rolesare the roles that the user has in the system. Currently roles aresupplier,investorandadmin. This attribute is updated by the platform-D onboarding API for the user on the UserManagement API. -
addressare the onchain addresses created for the user by the platform-D onboarding API afterKYC_SUCCESSstatus. This attribute is updated by the platform-D onboarding API for the user on the UserManagement API.
Please see webauthn background on
credential_id
KYC and Blacklist check
Impl gaya/gaya-kyx
After a value token is created, the user will be navigated to the KYC process. The KYC process depends on the nationality of the user. For Italian users, Gayadeed provides SPID identity proofing and Blacklist test, for other nationalities, Jumio is used for identity proofing and ComplyAdvantage.
The state of the KYC is stored in the Keycloak user attributes.
Please see details of iframe communication for the process of KYC by jumio here
KYC Status
The KYC states are tied to the sub.
stateDiagram-v2
[*] --> KYC_INIT
KYC_INIT --> KYC_PENDING
KYC_PENDING --> KYC_FAILED
KYC_PENDING --> KYC_SUCCESS
Verifiable Credentials Management
Impl gayadeed-vc-api
This service interacts with Paradym.id API services to create credential templates (see credential services for more template details), and stores the issued credentials on behalf for the users.
This service stores the credential for the users.
Onchain Transactions
In order for users to transact on Platform-D chain,
they must be able to sign a transaction with the controller pubkey associated in the Entity,
and they must present a verfiable presentation (derived from the verifiable credentials).
In core/services/wallet.services.ts we have signDirect which signs our RelayMsg for Platform-D Proxy.
FIXME: decide on integrating abstraction in sdk
As opposed to asking the user to use passkeys multiple times during transactions, we provide a reusable token (reuse for requesting presentations) for the user on login.
Note: The current (Berlin branch),
in login the wallet itself verifies the challenge just to verifies the pubkey correctness.
sequenceDiagram
autonumber
actor Platform-D Webapp
participant Platform-D API
participant AML/TR
Participant Gayadeed API/DB
Platform-D Webapp ->>+ Platform-D API: Transaction Details
Platform-D API ->> AML/TR: AML / TR Risk Analysis
AML/TR -->> Platform-D API: Analysis results
Platform-D API ->> Gayadeed API/DB: Tx Data Storage attempt (record keeping)
Gayadeed API/DB ->> Platform-D API: Relevant VC Presentation
alt Passed
Platform-D API ->>- Platform-D Webapp: call `navigator.credentials.get()` with `credential_id`
else Failed
Platform-D API ->> Platform-D Webapp: Error in AML / TR
end
Please see webauthn background on
credential_id.
Continuious AML Provider
Range is a Cosmos / IBC / Ethereum OFAC list specific risk calculation service. See their core offerings
Absolutely useful! They are looking for product partnership so pricing is very flexible.
Short term:
Continuous Crypto AML (transaction security API - RISK): They are specified in Cosmos / IBC and Ethereum (ofac list) / own research on scams, for our mainnet deployment (Neutron)
Medium term:
These are on top of Continuious Crypto AML
Users: They provide very useful UX API aka transaction security API - SIMULATION: they provide API to tell the user what will be the state of their wallet after they do the transactions (i.e. more NFT / Less fund / etc), but currently only on Osmosis, need intergration with Platform-D node.
Platform-D: Thread detection API - For IBC etc probably not so immediate (i.e. they usually do funds leaving bridges etc) but we can get them to monitor say --- ECB interest rates suddenly drop for 20% on unexpected dates from the oracle then something probably wrong. They also work with auditors to provide more vulnerable states. We will also know, for example if our yield curve have big changes then we know as well.
Crypto Travel Rule Provider
**WIP - update with NoteBene **
platformD ART and Data Dashboard
Dashboard
There are 2 main types of metrics
- ART: Assurance Reserve Trust data
- Overall Metrics: TVL, orderbook summary data and link to orderbook, invoice / investment data
2. Trading Data
- Total value locked (TVL): Sum of principles of all outstanding invoices
$$TVL=\sum_i Principle_i$$
Example: Centrifuge TVL (Top left)
- Assurance Resereve (AR) treasury size: Fees are generated when suppliers and investors interact onchain, these fees go into the Assurance Reserve that is onchain. (Since inception)
2.1 Orderbook Summary
Summary of orderbook, with a link to the orderbook
-
Total outstanding supply of invoices - outstanding volume of invoices that have been submitted to the order book, but have not been matched
-
Total liquidity from investment buy orders - outstanding volume of investments that have been submitted to the order book, but have not been matched
-
Predicted Yield Curve: An example of this is US Treasury, however, for invoices it will be max 3 months on the x-axis.
2.2 Assets Summary
Summary of traded assets
-
Daily maturing assets
-
Weekly maturing assets
-
Weighted average maturity (WAM) $$InvoiceWeight= \frac{Principle}{TVL}$$ $$WAM=\sum_i InvoiceWeight_i*T_i$$
-
Total buyers default risk - Italian public entity rating - Currently BBB, from source.
-
Outstanding assets and maturities (detailed) - if expanded by the user.
-
Late assets (volume and percentage of TVL)
-
Defaulted assets (volume and percentage of TVL)
Examples:
- centrifuge pool: On the top right there are some metrics for each pool. It is different to what we are doing but this is a view we found.
- rwa.xyz: Scroll down to investment and the table (sroll right) has similar metrics as an example as well.
3. Governance
The purpose of this page is to show the proposals and voting status, creating proposals. PT holders are able to create proposals
- DAOs can have different treasury and pools for community spending and token holders can hold them.
Examples:
- DAODAO: This app actually hosts a few Decentalised Autonomous Organisations (DAOs), the link is to one called Neutron. You can can the proposal details etc.
- CommonWealth: This app also hosts many different chain's governance. We have recently proposed for cheqd and you can see the onchain proposal here.
The details of governance functions can be found on the cosmos-sdk docs, which is what we will be using.
Calculations: Calculated Values
- Market cap (circulating)
$$Market Cap (circulating) = P_{pT} * S_{cir} $$
- Market cap (diluted)
$$Market Cap (diluted) = P_{pT} * S_{total}$$
- Total value locked ($TVL$)
$$TVL=\sum_i Principle_i$$
- Weighted average maturity ($WAM$)
$$InvoiceWeight= \frac{Principle}{TVL}$$
$$WAM=\sum_i InvoiceWeight_i*T_i$$
- Net assets value ($NAV$)
$$NAV=\sum_i \frac{RiskAdjCashflow_i}{(1+DR_i)^{T_i}}$$ , where $$RiskAdjCashflow=Principle*(1- POD*LOG)$$
- Timeseries of each investment and its annualised yield $$AnnualisedYield= \frac{Principle-InvestmentAmount}{InvestmentAmount}*\frac{365}{T}$$
$$AnnualisedReturns= \frac{\sum_{y=CurrentDate-1Year}Principle_i-InvestmentAmount_i}{\sum_{y=CurrentDate-1Year}InvestmentAmount_i}$$
- Calendar year returns - returns for the current year, example for year 2023: $$CalendarYearReturns= \frac{\sum_{y=01/01/2023}Principle_i-InvestmentAmount_i}{\sum_{y=01/01/2023}InvestmentAmount_i}$$
TBD:
Individual investor metrics
Returns
- Timeseries of each investment and its annualised yield $$AnnualisedYield= \frac{Principle-InvestmentAmount}{InvestmentAmount}*\frac{365}{T}$$
$$AnnualisedReturns= \frac{\sum_{y=CurrentDate-1Year}Principle_i-InvestmentAmount_i}{\sum_{y=CurrentDate-1Year}InvestmentAmount_i}$$
- Calendar year returns - returns for the current year, example for year 2023: $$CalendarYearReturns= \frac{\sum_{y=01/01/2023}Principle_i-InvestmentAmount_i}{\sum_{y=01/01/2023}InvestmentAmount_i}$$
Individual invoice indicators
| symbol | Args | On / Off Chain | Description | Location |
|---|---|---|---|---|
| $$Principle$$ | Invoice Principle | Off Chain | Invoice principle amount | Invoice parameter |
| $$InvestmentAmount$$ | Investment Amount | On | Order book matched price of a discounted invoice | Order book module |
| $$T$$ | Invoice Maturity | Off Chain | Time until invoice principle amount is due | Invoice parameter |
| $$POD$$ | Probability Of Default | Off Chain | Default probability of a buyer | Oracle |
| $$LGD$$ | Loss Given Default | Off Chain | Expected loss given default of a buyer | Oracle |
| $$DR$$ | Discount Rate | Off Chain | Cashflow discount rate | Yield curve module |
Backend Services
- Euro Credit States: update on Investor action fiat deposits and withdrawals
- Invoice States: update on buyer paid / is late / default
- Orderbook approval: update external market data and risk engine data
- Market Data: Update algo curve with external market data
Verifiable Credential Services:
- Update data like issuer list / revocation onchain if not over IBC
Oracle (Assurance, Yield Curve, Payments)
Fiat Payment Cash Leg
Before a fullly onchain stable coin payment system, there will be all / partial interaction with fiat banking payments.
flowchart TD
I(Investor Acc) -- Burn Euro Credits \n Pays Supplier --> S(Supplier Account)
I(Investor Acc) -- Burn Euro Credits \n Withdraw --> I2(Investor Other Bank Acc)
P(Payment Acc) -- Mint Euro Credits \n Buyer Pays Invoice --> I
I2 -- Mint Euro Credits \n Top Up --> I
- Payment Acc: the omnibus account for all invoice Buyers to pay into; Platform-D Ltd can instruct to send funds to investors
- Investor Acc: the investor's segregated account on Fabrick; Platform-D Ltd can instruct to send fundst to suppliers
Assurance
Yield Curve
Open Banking Integration
SPV Onchain Services
PD-SPV is registered on on several modules D-Chain as a DApp.
Interactions
Smart Contracts
- Notary Verifier: a simple contract that calls AVIDA sd-jwt verifier to verify the ODP verifiable presentation submitted by a user
- Notarised ODP: Stores information of the underlying ODP, i.e. the owner and states
- Orchestrator: the main contract with interfaces
- for
x/notaryto callPostVerExecto instantiate a notarised ODP contract - interacts with
x/tokenfactoryto create and burnSUprice syndication units to interact onx/orderbook - interacts with the instantiated notarised ODP contracts to instruct listing on
x/orderbookwhen specified by supplier - interacts with
x/orderbookto create orderbook for specificSU
- for
Module Registrations
- x/notary: for notarisation process for the ODP
- x/tokenfactory: for creating and burning
SU& EuroCredits tokens,SUare fungible across the same expiration date - x/orderbook: for creating price syndication orderbook for
SUand EuroCredits
Process Flows
sequenceDiagram
actor Supplier
participant M as module
participant SPV
participant DSD
participant ART
actor Investor
actor Obligor
autonumber
SPV ->> M: x/notary MsgRegisterAsset
Supplier ->> M: x/notary MsgNotarise;
M ->> DSD: verify
DSD -->> M: result
M ->> M: notarise and burn DTs
M ->> SPV: on notarise
SPV ->> M: sell order
M ->> M: x/matchengine: add sell order to AON orderbook
Investor ->> M: x/matchengine: add buy order
M ->> M: x/matchengine: order matching
M ->> SPV: x/matchengine: on match
SPV ->> DSD: issue request
DSD -->> M: x/tokenfactory mint & assign securities
DSD -->> Supplier: payment
DSD -->> SPV: ISIN
SPV -->> M: x/notary update ISIN and owner
Obligor ->> SPV: payment
SPV ->> DSD: mature
DSD ->> M: x/bank burn securities
DSD ->> Investor: Payment
Implementation Details
x/notary DSD Verifier
The example verifier contract has the correct interface that the x/notary module calls.
Given that we are not using sylvia anymore(it is only a code generation tool), we can still use the d-foundation/protocol-contracts package for the types.
However the trait that the example contract implements will just have to be an enum in the ExecuteMsg entry point.
On the interface with AVIDA sd-jwt, we can look at the example contract in the AVIDA repo.
The verifiable presentation have to disclose the following fields.
- buyer: string
- value: coin
- maturity timestamp
- did_addr (string) expected instantiate2, code address
This has to be signed by a jwk that represents the SPV entity. Maturity timestamp > the current block time
Expected Verifiable Presentation
-
Query API / webapp logic to get odp_contract_address (instantiate2 address) with a salt for instantiate2 which is hash of:
- buyer VAT
- supplier VAT
- document type (invoice)
- progress number
- creation date (ddmmyyyy)
-
Offchain issue verifiable credential (ODP VC)
- (disclosable) buyer VAT
- supplier VAT
- document type (invoice)
- progress number
- creation date (ddmmyyyy)
- (disclosable) salt for instantiate2
- (disclosable) amount_due : coin (amount, denom)
- (disclosable) payment_due_date: timestamp
- (disclosable) odp_contract_addr: (from step 1)
-
Supplier submits ODP VP (derived from step 2 ODP VC) onchain to notarise, the ODP VP will disclose
- (disclose) salt for instantiate2
- (disclose) amount_due : coin (amount, denom)
- (disclose) payment_due_date: timestamp
- (disclose) odp_contract_addr: (from step 1)
-
notary verification passed, SPV orchestrator (recieves
postverexec: output_ver / input_verwhich is the VP) use instantiate2 to create the ODP Verified Object, SPV orchestrator checks thatodp_contract_addressis the correct one for the instantiate2 calculation. Populate with:- buyer VAT: string
- amount_due : coin (amount, denom)
- payment_due_date: timestamp
-
the ODP Verified Object will need to store in state
- (static) buyer VAT: string -(static) amount_due : coin (amount, denom)
- (static) payment_due_date: timestamp
- (Updatable) owner supplier address
Notarised ODP Contract
This smart contract is instantiated by the Orchestrator post notary verification.
The purpose of this contract is to provide metadata to the owners of the PTs.
PTs are issued based on the underlying ODP that this contract represents.
If the ODP is for 10,000 Euros, there will be 10,000 x 1000 mPTs issued.
i.e. 1 mPT = 0.001 Euro.
States
status
Current status of the ODP
Type: Enum - Notarised, Issuance Requested, Issued, Matured, Redeemed, Default
This can only be updated by the ODP Admin.
State Transitions
stateDiagram-v2 [*] --> Notarised: `MsgNotarise` Notarised --> IssuanceRequested: Updated by SPV on price match IssuanceRequested --> Issued: Issuance Request accepted by DSD Issued --> Matured: `maturity_timestamp` is reached Issued --> Redeemed: `PT` holder(s) are paid Matured --> Redeemed: `PT` holder(s) are paid <br /> post maturity Matured --> \Default: Assurance reserve kicked in
odp_admin
The admin address for this ODP contract.
This address does not have to be the owner of the ODP itself.
This address can update the status of the ODP.
Type: Address
owner
Current owner of the underlying ODP
Type: Address
balances
A mapping of PT holders and the number of PTs they hold.
PT by default is in the unit of mPT (milli PT)
Type: Map - Address -> uint256
value
The value of the underlying ODP. In the case of e-Invoices, it is the recievable amount.
Type: coin{ "denom": "EUR", "amount": 10000 }
maturity_timestamp
The date when the ODP matures. In the case of e-Invoices, it is the due date of the invoice.
An ODP state will change by endblocker hook to Matured if the maturity_timestamp is reached.
This timestamp is feed in as epoche seconds as part of the input for notarisation.
Type: Expiration - a cosmwasm type with timestamp
notarised initiator
This is the address of the supplier who initiated this process. This is forwarded by the notary module.
Type: Address
Messages
Queries
Orchestrator
This is the SPV orchestrator as a placeholder for now to instantiate notarised ODP contracts.
Business Process
Actors
Supplier
graph LR; ob[onboarding]-->b2g[B2G e-invoice]-->not[notarisation]-->neg[negotiation]-->co[cashing out]
Buyer
graph LR; ob[onboarding]-->b2g[B2G e-invoice]-->not[notarisation]-->pay[pay]
Investor
graph LR; ob[onboarding]-->or[onramp]-->invest[invest]-->div[divest]-->offr[off ramp]
FT Fund
OnBoarding
B2G e-invoicing Process
Notarisation
Negotiation
Cash out
Pay
On Ramp
Invest
Divest
Off Ramp
Onboarding
Jump to specific onboarding processes
The general purpose of onboarding is to:
- gather information (for checks and archival)
- facilitate and store digital signatures (to verify formal agreements, declarations)
- facilitate and record keep 3rd party service provider verification (KYC / AML / etc)
The process of onboarding ends with issuance of verifiable credentials to the users. Depending on the role, different information / process may be performed in order to issue one or multiple verifiable credentials.
There are 2 types of verifiable credentials onchain:
- Identity: This is required for all transactions
- Invoice Notarisation: This is required to notarise eInvoices onchain, required only by Suppliers
There are 5 role types in Platform-D in terms of onboarding with common prerequisites, aka [Identity Credential]:
- Suppliers: eInvoice issuers, the suppliers of goods and services, holds both Invoice and Identity credentials
- Buyers: Payers of eInvoices, the buyers of goods and services, holds Identity credential
- Investors: The buyers of the securities - DTs, holds Identity credential
- Validators: The Platform-D node validators, holds Identity credential
- Administrators: The Platform-D authorised administrator accounts (including oracles), holds Identity credential
Identity Credential (Common Prerequisite)
The credential schemas and definitions include:
- Derived physical person identity
- Legal Person Identity
- Power of representations
- PeP (politically exposed person)
- CFT (Combating the Financing of Terrorism)
- Adverse Media (aka Crime)
Supplier Onboarding
Pre-requisites:
-
Platform-D appoints Gayadeed as trusted Issuer, with credential schemas and defs:
- Derived physical person identity
- Legal Person Identity
- Power of representations
- PeP (politically exposed person)
- CFT (Combating the Financing of Terrorism)
- Adverse Media (aka Crime)
-
Platform-D establishes (via Gayadeed) integration with one or more public Notary (ideally one for each district - or via Notartel) for the credit transfer certification via public act.
-
Platform-D set up the supplier on-boarding procedure which includes:
- AML/CFT of supplier legal representatives
- Mint of NFT smart contract for the supplier (where invoice tokenId will be defined)
Supplier onboards to Platform-D
- Gayadeed verifies:
- Derived physical person identity (via SPID, CIE)
- Legal Person Identity (via Infocamere API)
- Power of representations (via Infocamere API)
- (in case of joint powers) Repeat the process for any other legal representative
- PeP+CFT+AM (via Sefin API)
- Financial Suitability Questionnaire
- ML Questionnaire
- Supplier signs Platform-D agreement with attachments with FEQ. These includes:
- Public Notary of reference
- Fees acceptance
- Terms of Service (using the wallet, etc)
- Prospectus (DT)
- Supplier onboards with Fabrick for Open Banking API. The purpose of this is to
- allow Platform-D API to query their accounts incase of Buyer wrongly deposited
- allow user to display their balance
Buyer Onboarding
Investor Onboarding
The onboarding of investors includes the following steps:
- The initial onboarding (KYC / AML / T&C) that is required for all roles
- The onboarding of financial suitability test
- The creation of escrow account in Fabrick (Banking Partner)
- (When wanting to invest) they top up of Euro Credits.
Context: the concept of Euro Credits is only valid before a stable coin
2. Create Escrow Bank Account
This step is a redirect from the Platform-D webapp user flow to the partnering Fabrick bank's UI for account creation.
3. Top Up Euro Credits
This is an Oracle MINT action, see Fiat Payment for other Euro Credits actions
flowchart TD
Investor -- Invest Fiat --> Bank
Investor --Invest Crypto --> o(Onchain Account)
o -- Offboard --> c(CEX)
Bank --> e(Fabrick Escrow Account)
c --> e(Fabrick Escrow \n Segregated Account)
e -- Emits Events ---Oracle
Oracle -- Mints Euro Credits --> Protocol
Investors are presented with the correct information to fund their own Escrow account which they created in Step 3.
B2G e-Invoicing process
actors:
- Supplier: a private or public administration company incorporaed in italy
- SDI (Sistema di Interscambio - Data Exchange system): back end service managd by a company named SOGEI on behalf of the Italian Ministry of Finance
- Buyer: a public administration company incorporated in italy
- Agid: italian competent authority for the e-invoicing specs
- e-invoicing intermediary: a third party private company offering web services to facilitate E-INVOICE management (preparation, digital signature, sending and receiving messages through the SDI)
e-invoicing process high level overview
sequenceDiagram
Supplier->>Supplier: prepares and signs E-INVOICE
Supplier->>SDI: sends signed E-INVOICE
SDI->>SDI: verifies E-INVOICE and create metadata
SDI->>Buyer: sends E-INVOICE and metadata
SDI->>SDI: prepare and signs RECEIPT OF FILE DELIVERY TO RECIPIENT
SDI-->>Supplier: sends RECEIPT OF FILE DELIVERY TO RECIPIENT
Buyer->>Buyer: E-INVOICE formal and busness internal cheks
Buyer->>SDI: senda CUSTOMER NOTIFICATION OF OUTCOME (acceptance or rejection)
SDI->>Supplier: senda CUSTOMER NOTIFICATION OF OUTCOME
type of messages and formats:
E-INVOICE and metadata
B2B E-INVOICEs are XML files complying to the "FatturaPA" format and always requires Qualified Electronic Signature.
The Signature may of two alternative types:
- (XAdES) XML Signature (the signature is included in the XML)
- (PAdES) P7M Signature (the signsture is external to the file and both the file and the signature are wrapped in a mime-type envelope)
notifications
notifications are xml files complying to the Data Exchange System Specigifations
Notifications types that are relevant for platform-d are:
- RECEIPT OF FILE DELIVERY TO RECIPIENT (see par. 1.2 of the specs): attests the succesfull delivery of the E-INVOICE to the buyer. It includes a digital signature by the SDI.
- CUSTOMER NOTIFICATION OF OUTCOME (see par. 1.5 specs): attests the formal acceptance or rejection of the E-INVOICE.
E-INVOICE examples
- E-INVOICE (signed by Supplier or Intermediary)
- RECEIPT OF FILE DELIVERY TO RECIPIENT (signed by SDI)
- CUSTOMER NOTIFICATION OF OUTCOME (optionally signed)
ToDos
- add the case where the outcome isn't receinved: in this case the time ut notification is mandatory (in order to avoid a negative result, hidden by the supplier plus forgery of buyer identity)
- add another type of notification as required (in case of lacking of the outcome)
- if either the outcome or the timeout notificaiton aren't presented by the supplier, the notarisation cannot proceed
- add checking via AISP account that the e.invoice hasn't been paied at time of notarisation and negotiation
eInvoice Origination
This is the process that is required to collect all the required data, documents and required signatures for a trusted issuer to issue the Invoice Notarisation Credential.
PT Notarisation Dossier Type
This is a specific Dossier Type provided by Gayadeed. The overall process is as such:
sequenceDiagram
Supplier->>Gayadeed: create PT Notarisation Deed
Supplier->>Gayadeed: Select Buyer and upload invoice and notification
Gayadeed->>Buyer: invite to participate and sign
Buyer->>Gayadeed: Log in and perform Identification
Buyer->>Gayadeed: review documentation and sign (QES) CTA Letter
Gayadeed->>Supplier: invite to sign
Supplier->>Gayadeed: review and sign (QES) CTA Letter
Invoice Origination Data Package
graph LR
dtdp[Invoice Origination Data Package]
dtdp --> einv[signed eInvoice]
dtdp --> not[signed notification]
dtdp --> ctal[Mutually signed CTA Letter]
dtdp --> ctalmd[CTA letter metadata]
dtdp --> md[einvoice metadata]
dtdp --> gd[Gayadeed verification metadata]
md --> amount
md --> suppVat
md --> buyerVat
md --> expiryingDate
md --> issuingDate
md --> progressNumber
md --> originalBankAccount
ctal --> supplierDateOfSigning
ctal --> buyerDateOfSigning
ctal --> paymentlink
ctal --> newbankAccount
ctal --> PaymentDate
gd --> auditTrailID
gd --> auditResult
Credit Transfer Authorisation Letter (CTA)
This is a PDF document, once signed by both the Supplier and the Buyer with a QES, the Buyer:
- formally certifies that all the attachment provided are correct (einvoice and notification)
- formally certifies the existence and the validity of the credit in regards to the e-invoice
- formally authorises the Supplier to transfer the credit
- formally acknoledge to pay its debit at maturity, via the payment link provided
- formally accept all the terms and conditions applicable in case of delayed payment
the CTA letter is signed through Gayadeed, assuming that both the Supplier and the Buyer succesfully completed their onboarding on Platform-d
Open Issues
- Credit assignment by the public administration (PA) requires:
- Explicit acceptance by the PA (need to on-board the list of one or more Signatories from the Buyers).
- The form of a public deed or private contract between the parties, authenticated by a public notary (Gayadeed may be inlcude signature by a public notary - can this be a PAdES-T signature?))
- eInvoice Acceptanceby the Buyer via SDI is
- Optional
- May arrive within 15 days from the delivery
- In case the acceptance ntification isn't produced by the Buyer, the SDI automatically notifies the supplier with a meet of the deadline notificatoin
- eInvoice explicit Acceptance Deadline expiration does not determine implicit acceptance of the debt by the PA
- Supplier-side signature powers: how to determine them automatically (Chamber of Commerce "Infocamere" API)
- Buyer-side signature powers: how to determine them automatically? (API Infocamere?)
- How to prevent double spending of the invoice (Air protocol + optional "Notes" field of the electronic invoice containing references (did) to the NFT smart contract for the supplier in question)
DSD
DSD Onchain Services
DSD Main Contract
*MFT
Interaction with the x/tokenfactory and x/orderbook
Initially ODP related PTs are not fractionised, i.e. investors must buy and sell PT equivalent to the entire e-Invoice.
DSD Offchain Services
Oracle
Reporting
Testnet Theodoric-II Scope
Overview
Theodoric-II is the testnet of dchain.
Recap of Theodoric-I
In Theodoric-I, we tested the following features.
Theodoric-II Scope
Building on the SSI-enabled validator onboarding, 2 layers governance and decentralisable verifiable credentials issuance, Theodoric-II will focus on the following features:
-
Tokenomics: The burning and minting of DTs is designed to provide supported applications with a predictable cost and to provide DT holders with security lending rewards that aligns with the success of the network.
- Minting: The rewards schedule is designed such that DT reaches a maximum supply of 100 billions DTs. The testnet will start wit 80 billions DTs and simulate an accelerated schedule for unlock, minting and reward reduction.
- ** Burning**: The burning of DTs will be tested by platformD application.
-
Abstract Account: Allow users to sign up and complete onchain transactions with webauthn.
-
Staking: Using abstract account to complete staking related transations
-
Governance: Voting in the governance on Dchain. In order to vote, requires staking DTs AND valid verifiable presentation as part of the voting transaction. Vaildators have the voting power proportional to their own staked DTs only, delegated DTs can only be used to vote by the delegators themselves.
-
platformD initial end-to-end flow: The initial end-to-end flow of platformD application will be tested on Theodoric-II. This includes burning of DTs as part of the utilities fees of using modules on Dchain.
Testnet users onboarding
Initial account creation (pre-genesis)
sequenceDiagram
autonumber
actor dh as DT holder
participant kc as Keycloak
participant be as platformD Backend
participant Dchain
dh ->> kc: create new account (with webauthn)
kc ->> be: event hook (account created)
be ->> be: predict proxy contract address
be ->> kc: update user with contract address
note over be: batch create vesting <br /> create proxy with authenticator contracts
-
In the testnet we will allow user to just go to demo.platformd.io and create a new account. We can do this by allowing self-registration in keycloak. We will ask for email and require webauthn registration, we can ask for password if we want, but must have webauthn. See the setting of the keycloak realm for just webauthn and no password.
-
When the account is created, we want to have a hook to call the backend to predict the proxy contract address. It looks like some sort of java event listener is needed. I asked grok and I think its pretty standard. Here is an example I found.
-
The backend that gets called will predict the proxy contract address. This actually requires a few things.
- We need to assume an "platformD admin" dchain address that will deploy the proxy contract, a salt (which we need to store to make sure we use the same one when we create the proxy contract), and I think we also need to have the code id and also the message? (check out Instantiate2 logic, I think we can use
fix_msgoption to make it independent of instantiation message?), see x/abstractaccount/keeper/msg_server.go l:75
- We need to assume an "platformD admin" dchain address that will deploy the proxy contract, a salt (which we need to store to make sure we use the same one when we create the proxy contract), and I think we also need to have the code id and also the message? (check out Instantiate2 logic, I think we can use
-
Update keycloak with the new address. We want the frontend to have such address in the jwk to pull balances in the future.
@Andrew: here are some previous work that you should checkout before implementation:
- The backend can in fact get the
credentialDatafrom Keycloak user data. I did it in rust here - This
credentialDatashould be the correct data to be used in the proxy authenticator, some details on this:- As a reference ONLY (vectis has changed significantly since we wrote this webapp) - We directly used the browser to create the credential here, not keycloak. but insteaof using
this.navigator.credentials.create, I expect keycloak will do all that and store theAuthenticatorAttestationResponsein the credentialData field of the user. Keycloak should be storing the same data the type from MDN Reference. - You can see the end to end flow of using the passkey-cli to create a credential and then use that to sign a challenge - the challenge being the hash of the bytes from the cosmos transaction in the test here
- As a reference ONLY (vectis has changed significantly since we wrote this webapp) - We directly used the browser to create the credential here, not keycloak. but insteaof using
Software Components Selection
Platform-D Chain
Identity
Application Specific Blockchain Stack
Platform-D is built on Cosmos-sdk with consensus by CometBFT & smart contracts framework by CosmWasm.
Modules and Smart Contracts
Cosmos-sdk is the application layer of a blockchain node and communicates with the underlying networking and consensus layer - CometBFT. As the name suggests, it is a SDK and applications can add modules to it to interact with the states.
One notable module that any application specific blockchain can add is x/wasm. It is a Cosmos-sdk module that contains the Go binding (wasmvm) to the underlying CosmWasm-VM, which rus the CosmWasm smart contracts.
Given there are now 2 ways to customise functionalities on the blockchain, the design decision is where should such business logic lie for flexibility and efficiency.
Flexibility
One of the advantages of using CosmWasm over other smart contract frameworks is the ability to reuse other libraries written in rust (with some limitatiosn), in particular - many high quality cryptographic libraries.
Another way to reuse other libraries / keep up with newest development from the wider developer communities is to be able to load WASM code in the blockchain node. At the time of writing, WASM loader is not available in the runtime of Cosmos-sdk. However, in the 2024 roadmap the contributors include both cross language WASM loader & exploring alignment with CosmWasm.
With all these developements, the initial MVP of Platform-D will align with the Cosmos-sdk roadmap, it will be flexible by incorporating the x/wasm module.
It is important to note the EVM runs bytecodes that are customised, is very restrictive in its instruction and memory that makes it very difficult to write safe, efficient smart contracts. In addition, applications must be specifically built for the EVM, making it impossible to leverage external libraries outside of the ecosystem.
Efficienty
Last updated: Belsy Yuen, 28-11-2023
Inter-Blockchain Communications (IBC)
One of the primary advantages of building the Platform-D on cometBFT, cosmos-sdk & CosmWasm is the native support for IBC protocol, which is a trust-minimizing and permission-less solution for interoperability bridge.
IBC minimises third-party risks
Bridges with centralised third parties
Most bridge solutions requires a trusted third-party to relay messages between chains and/or to onboard a new chain. This is a valid solution for specific use cases, notably Circle's Cross-Chain Transfer Protocol, which requires Circle as an entity must be the only master minter of USDC. This means that:
- Chain Onboarding: Circle is the only entity that can add a new chain to the CCTP ecosystem
- Permission and Trust: Circle is a centralised entity to "burn/lock & mint" from one chain to another
It is also worth noting that there is a trusted implementation of IBC by using a centralised / multisig Light Client Proxy verification with [TEE] offchain then using the TEE to submit the verification onto another chain. There is ongoing project with this method for Cross-Chain settlement of Stable Coin with banks in Japan.
Permissionless and Trustless bridging
However, outside of the stable coin application, it is important to minimise third-party risks when it comes to chain interoperability. IBC allows for each implementing chain to verify the light client of the other, via cryptographic proofs; these proofs can be submitted onchain by anyone and will not depend on the bridging entities.
If the states proofs are incorrect, e.g. the client hash does not reflect the previously accepted one, then the submission will fail, therefore finality is set. Because of the design of the consensus algorithm implemented in cometBFT, finality is provided per block and therefore the updates that are required on the remote chain light client is final.
IBC allows for normal users of either chain to run a stateless IBC-relayer, implemented in different languages and maintained in open-source (hyperspace-relayer, ts-relayer, hermes (rust), cosmos/relayer (golang), yui/ibc-relayer), to submit state updates from one chain to another chain. In simple terms, as long as the chains themselves are considered trusted (e.g. requires verifiable credential, decentralised, has qualified validators, etc), then interoperability via IBC minimises third-party risks.
Proven Technology across multiple ecosystems
IBC is a proven technology with ~70 Cosmos-sdk based chains already connected and over [25B USD transacted] with no , others are being developed / used described below:
| Projects | Target Ecosystem | Details |
|---|---|---|
| Polymer Labs | Ethereum | |
| Union | Ethereum | zkIBC proof of ed25519 curve (consensus) verification, not state transition |
| Electron Labs | Ethereum | |
| LCP - Light Client Proxy | Ethereum | Offchain [TEE] for light client verification & ibc-solidity contracts on EVM chains |
| Hyperledger Fabric | yui-fabric-ibc | |
| Corda | yui-corda-ibc | |
| Ethereum | [yui] | |
| Landslide | Avalanch Subnet | A subnet in Avalanch ecosystem building on the forked Tendermint consensus |
| Composable Finance | Polkadot / Kusama | Unique project bridging Polkadot & Kusama with IBC-substrate Pallet |
| Polkadot | Production | |
| Ethereum | (Testnet) | |
| Solana | In development |
IBC on Platform-D
Platform-D is an application specific chain that runs the business logic and has qualified validators to validate and replicate state change. For external settlement or interoperability, i.e. if we want to consider Platform-D states to also update states on external blockchains for any reason, or would like to interact with other blockchains, Platform-D can either utilise [TEE] for IBC verification (where it requires existing validators to verify), or have the out-of-the-box IBC module in cosmos-sdk to interact trustlessly with the various open-source relayers.
It is worth noting that any external state updates via IBC on Platform-D also follows that same requirements as any transactions, i.e. only those with verifiable credentials.
Last updated: Belsy Yuen, 28-11-2023
Verifiable Credentials
W3C
sd-jwt
AnonCreds
Background
Some notes on how some of the modules work in Cosmos-SDK which is used in D-Chain.
Standard process flow diagrams
(NOT D-Chain specific)
Delegations Flow (cosmos-sdk v0.50)
sequenceDiagram
participant Delegator
participant Validator
participant OtherNodes as Other Nodes
participant Consensus as Consensus Engine
participant Staking as x/staking
participant Slashing as x/slashing
participant Distribution as x/distribution
participant Mint as x/mint
participant Auth as x/auth
Delegator->>Staking: Delegate tokens
Staking->>Validator: Update stake
loop Each block
Mint->>Auth: Mint new tokens
Auth->>Distribution: Transfer minted tokens + fees
Distribution->>Distribution: Calculate rewards
Distribution->>Validator: Distribute validator rewards
Validator->>Delegator: Distribute delegator rewards
end
rect rgba(0, 0, 0, 0.1)
Note over OtherNodes,Slashing: Evidence Submission
OtherNodes->>Slashing: Submit double signing evidence
Consensus->>Staking: Report missed blocks
Staking->>Slashing: Check for downtime at end of window
end
rect rgba(0, 0, 0, 0.1)
Note over Slashing,Distribution: On valid evidence
Slashing->>Validator: Slash
Slashing->>Distribution: Update rewards
end
Delegator->>Distribution: Withdraw rewards
Delegator->>Staking: Undelegate tokens
rect rgba(0, 0, 0, 0.1)
Note over Staking,Distribution: Governance can adjust parameters
end
Minting Flow (cosmos-sdk v0.50)
sequenceDiagram
participant Mint as x/mint
participant FeeCollector as Fee Collector<br/>(x/auth)
participant Distribution as x/distribution
participant Validators
participant Delegators
rect rgba(0, 0, 0, 0.1)
Note over Mint,FeeCollector: Minting and Fee Collection
Mint->>FeeCollector: Mint new tokens
Note right of FeeCollector: Minted tokens sent to<br/>fee collector account
activate FeeCollector
FeeCollector->>FeeCollector: Collect transaction fees
deactivate FeeCollector
end
rect rgba(0, 0, 0, 0.1)
Note over FeeCollector,Distribution: Distribution Process
Distribution->>FeeCollector: AllocateTokens()
FeeCollector-->>Distribution: Transfer all balances
end
rect rgba(0, 0, 0, 0.1)
Note over Distribution,Delegators: Reward Distribution
activate Distribution
Distribution->>Distribution: Calculate rewards
Distribution->>Validators: Distribute validator rewards
Validators->>Delegators: Distribute delegator rewards<br/>(minus commission)
deactivate Distribution
end
Primary Market Orderbook
There is a 2 steps process for creating a sell order on the orderbook by the supplier.
- The supplier signs and expresses the slippage (percentage) and limit order on discount
- The offchain oracle - supported by the risk calculation engine approves / declines the the order
For users of the orderbook, When adding their orders to the orderbook, they can define slippage (percentage) and limit order (acceptable discount / yield) depending on their circumstance.
Platform-D Orderbooks
At the MVP stage we will implement a module that is the CLOB and will use EndBlocker execute all market orders / matching orders in the same block for DTs in a FBA way.
State
Messages
Keeper
Params
Design references: the state-of-the-art
There are several blockchains in the Cosmos Ecosystem that are designed for fast trading with orderbooks, as they are state-of-the-art, we will summarise their innovation and what Platform-D has for its MVP.
The below are all Central Limit Order Book (CLOB).
| Protocol | CometBFT features | FBA | Additional Info |
|---|---|---|---|
| dydx | Upcoming: uses ExtendVote for validators to collaborate to agree on block (instead of just single proposer) | FBA for all the trades in the block (voted in in the previous block) | Orderbook is offchain in memory and managed in the CLOB in the sdk |
| Sei | - Optimistic Block Processing - Intelligent Block Propagation | FBA for all market orders in the same block for the same orderbook | At EndBlocker hook, all market transactions go through the DEX module as the main order matching engine (including FBA) |
| Injective | N/A | At EndBlocker hook, transactions in the Exchange module are matched in FBA fashion |
x/wasm
This module supports CosmWasm smart contracts.
Introduction
There are much information around CosmWasmo on the internet, here is a simple summary to provide some very high level overview of what is under the hood.
The overall design is as such:
- wasmvm: This is the Go code that imports cosmwasm-vm via cgo
- cosmwasm-vm is compiled lib (
.so,dylib,.dll,.a) to be linked via cgo - The APIs for this is in
internal/api
- cosmwasm-vm is compiled lib (
- cosmwasm-vm: This is written in rust uses wasmer embedded runtime to run the CosmWasm smart contracts
NewApp
When the node starts, along with creating all module keepers,
the wasmKeeper is also created.
This calls [newVM] which creates cosmwasm VM which has the wasmer engine,
the runtime for the CosmWasm contracts.
This VM is used for the execution / code store / query etc.
Transaction flow
On StoreCode the wasm file is compiled (into executable code).
Both the original wasm and the executable code are stored.
When there is a transaction to execute,
a contractInstance is created by loading the existing contract state / code.
Contract address and other relevant info along with prefixStore for that contract are then passed into the C code compiled from cosmwasm-vm for Execute in wasmvm -> CosmWasm-vm via the cgo import.
WebAuthn
Background
The is a tech follow-up on the discussions we have had is around is a user allow to create more than a single account with Vectis on the same device / foundational ID.
Given the current flow in Onboarding,
the flow of creating a webauthn credential happens BEFORE any account is created,
this means that in the PublicKeyCredentialCreationOptions,
that the PublicKeyCredentialUserEntity has a randomly generated id.
This id MAY be used in authentication,
i.e. when the user Login,
or in our case,
signs a transaction,
we can leave the CredentialDescriptor empty.
In the [discoverable credential] model (which we are using),
this means that the passkey are returned for all the credentials relevant to our rpID.
On the other hand,
if Login requires interaction with a Vectis API,
i.e. in the case to unlock for VC,
then, it is possible to request a specific id that was created in Onboarding.
This method does not prevent creation of multiple accounts, unless we have get or create type api available, however, this is still only in discussion.
Example
ICP has a good example that we need to upgrade to, getting the credentialID so there will only be 1 credential you can login with, even if you have created a few different accounts (given you entered the correct id).
Platform-D Glossary
Foundation
The entity that is the foundation in Platform-D
Notarised Invoice
eInvoices that are notarised on the Platform-D chain.
DT
The native govenance tokens for Platform-D
PT
Securities token
Verifiable Credential
(TODO) Digital credentials that are cryptographically proven to be issued by a party.
Verifiable presentation
A verifiable presentation derived from the verifiable credential
Invoice Notarisation Credential
This is the verifiable credentials issued by a Trusted Issuer that are used to verify that the offchain-collateral of the eInvoice had been checked and are valid. The offchain-collateral [DT Data Packet]
Identity Credential
This is the verifiable credentials issued by a Trusted Issuer that are used to derive proof presentation for interacting with Platform-D upon doing KYC & AML checks.
Trusted Issuer
Any Platform-D appointed trusted issuers - such as [Gayadeed], will be able to issue [verifiable credentials] that is recognised by Platform-D systems.
Pratically speaking, this means that the issuers' DID document (Public Keys) are made available onchain.
DT Data Package
This is a data package that is comprised of artifacts required for a trusted issuer to issue a verifiable credential that is used in the notarisation process of the electronic invoice to an onchain [invoice] instance.
The data must contain:
- Supplier signed (Qualified Electronic Signature) invoice with machine readable data
- Notification of acceptance (of credit transfer)
(To be completed)
SSI driven consensus with RWA (Invoice) staking
Background and motivation
Invoices are assets that do not create yield. We want to change that.
See flow diagrams for processes
Design perimeter and assumptions
There are the native staking bonding_denom that is DT.
To avoid creating another token which complicates the system and divert values from DT,
which should represent the security of the network,
we have decided to translate invoices into DT for the purpose of staking.
However, there are very distinct differences between staking DT and staking invoices. This is because the expected risk and reward are different.
Considerations specific to invoice staking
- Invoice value are in fiat (Euro) and must be paid in fiat via the banking system of choice
- Suppliers and Buyers are not necessarily DT holders
- Suppliers are expected to take risk on the yield derived from invoice staking, which would have been zero if not staked anyway
Distinction between DT and invoice staking
| DT staking | Invoice staking | Rationale | |
|---|---|---|---|
| Holdings | Already holds DT | Notarising invoices which are translated into staked DT, cannot transfer invoice derived DT | invoices -> DT is allowed for the purpose of providing security service to the network, it is not an exchange between assets |
| Delegate | Delegate desired amount of DT to validator | Notarise invoice and all minted DT are by default staked | We cannot allow partially staking of invoices, the full face value of the invoices must be fully staked, but it can be delegated to different validators |
| Expected Risks | DT rewards rates vs Slashing of validator | No slashing of invoice face value, only on rewards | Suppliers is providing their invoices as a service for the security of the chain, their risk is on the potential yield (i.e. service fee) and not the actual invoice value |
| Rewards | Reward rate depends on the inflation and desired bonding ratio minus validator commission | Rewards are shared between supplier and validator node (and therefore the delegators) | Since there is no unbonding period or slashing of the face value, rewards are shared between the validator and the supplier |
| Reward distribution & collection | Reward distributed and collectable at every block | Reward distribution and collection on invoice payment only | This prevents invoice default or fraudulant invoices minting DT rewards |
| Unbonding Period | Chain unbonding period | staked DT can have unbonding period, rewards will be distributed following unbonding decision | Security of the network is reflected by the value of the assets staked, if the invoice has been paid, the staked DT must at least be unbonded then burnt or burnt immediate, see section below for details |
| Undelegate | Can undelegate DT and withdraw after unbonding period | Cannot undelegate invoice derived DT, only exit when buyer pays | DT derived from notarised invoices are not transferable, they are minted on staking and burnt on payment, reflecting the ownership and asset value of the invoices on chain |
* This point must be carefully analysed, unbonding period is there to:
- prevent short range attacks (double spending) where validators can be slashed during the unbonding period
- ensure the stability of the network (prevent sudden changes in the validator set)
- ensure "skin in the game" for validators and delegators (prevent vote and exit, quickly unbond to validate another network) scenarios
Economic model and financial incentives
Suppliers (Invoice issuer)
On completion of the goods or services delievered to the Buyer, the invoices become an asset on the balance sheet of the suppliers - account recievable. However, there are no ways to derive any yield from this asset.
There are a few incentives for the suppliers to stake their invoices:
- Service Fee: By providing the option for staking the invoice, the supplier is able to derive service fees (yield in DT). It must be designed such that suppliers do not put their assets at risk (Buyers are still liable to pay the invoice via traditional banking services or in the near future - regulated stable coins). The yield the network provides compensates for the the service the supplier provides to the network - security.
- Speed of payments: D Chain should be encouraging buyers to pay early in order to attract suppliers. A early payment bonus (defined by params) is a feasible solution
- Other services: Notarised invoices are a proof of the transaction between the supplier and the buyer. This can be used for other services - discounting via Platform-D DApp
- DT rewards: Suppliers invoice staking service fees are paid in DT which will supplement their future transaction on D Chain, also allowing them to also stake their DT for additional yield
Buyers (Invoice payer)
Buyers are not directly involved in the staking process however, there are benefits for them to be involved:
- Early Payment Bonus: the system encourages faster payments by introducing an Early Payment Bonus to the buyers with a set params of invoice notarisation date
- Better offers: suppliers knowing that the buyers can provide track record (of payments) and that are willing to allow them to use their invoices (on DChain or other services) will be more likely to provide better offers (e.g. discounts, better payment terms, etc.
- Other services: Buyers can may use other services, such as be investors on Platform-D DApp, which supplies their treasury with high quality short term assets
Validators
Validators are not directly incentivised or involved by invoice staking, however, they may benefit from:
- invoice notarisation transactions bringing more fees to the network
- self-delegation (see next section)
Delegators of DTs
Delegators of DT has more risk than invoice stakers:
- has to wait for unbonding period
- can be slashed
However, they are also able to be more flexible in their stakin:
- deciding on unbonding date
- collecting rewards at every block
They must be rewarded better than the invoice staking of the same amount of DT
Immediate or unbonding period of invoices?
Given that the unbonding period is actually introduced for security measures, we can keep that for invoices.
Pros:
- gives a chance for the reward to be slashed (so that other delegators are not as affected)
- delays reward distribution to supplier
- follows the protocol of normal DT staking
- no extra voting power when unbonding
- no need to discount total voting power because it follows the same protocol as normal DT
Cons:
- delays reward distribution to supplier (from supplier point of view)
- the invoice no longer exist, we are just delaying the burn (which can be a good thing)
Point of Considerations:
- when tokens unbond, the voting power of the validator decreases but everyone elses increases
- during unbonding period, the unbonded tokens can still be slashed
- during unbonding periods, the tokens are already inactive, removed from total active staked
- during unbonding period, voting not allowed
- the rewards are not distributed to the unbonded tokens
Non-Slashable invoice face value staking
Regardless on unbonding or not The problem of Non-Slashable invoices causes an inbalance in the system, where native DT stakers will have to pay for the slashed amount.
Example
Let's consider an example without yield for now.
Block H: Total active staked = 100, 000 - Buyer pays, invoice DT tokens are unbonds (10,000) (this is fine because it will just be burnt after unbonding period)Block H + 1: Total active staked = 90,000, unbonding is 10,000Block H + 10- Validator gets slashed for double sign atBlock H - 10(when invoice DT were still actively staked), penalty is 5%. Total active staked at validator is now 90,000*0.95 = 85,500 and total unbonding is 10,000*0.95 = 9,500Block H + unbonding-ends- 10,000 tokens must be burnt but only 9,500 tokens are available, the remaining 500 tokens comes from the actively staked pool, i.e. remaining is 85,000. The remaining delegators has additional stash of 500/85500 = 0.58% of their tokens.
In this case, the reward pool must lock in the potential reward on the invoice DT portion because it might not be distributed if the invoice is not paid. Once it is paid, then the reward is split between the supplier and the shares in the validator (delegators)
This scenario breaks down when the validator does not have sufficient total active staked DT from normal staked DTs (NOT invoice derived DTs). Imagine the scenario that (if there are zero rewards, or rewards is less that 405/10000 = 4.05% of the total staked DTs)
Block H: Total active staked = 10, 100 - Buyer pays, invoice DT tokens are unbonds (10,000) (this is fine because it will just be burnt after unbonding period)Block H + 1: Total active staked = 100, unbonding is 10,000Block H + 10- Validator gets slashed for double sign atBlock H - 10(when invoice DT were still actively staked), penalty is 5%. Total active staked at validator is now 100*0.95 = 95 and total unbonding is 10,000*0.95 = 9,500Block H + unbonding-ends- 10,000 tokens must be burnt but only 9,500 tokens are available, the remaining 500 tokens comes from the actively staked pool, but only 95 are remaining.
The following graph shows the yield of a specific case where
- 100,000 DT are staked, 10% yield applied, 5% slashing, 0% commission
- ratio of those DTs are invoice derived (x axis)
- yield of the delegators relative to the total staked invoice DTs (y axis)
- part of the yield is split between the supplier and the validator (delegators)

Fund Limit Pricing Engine (FLPE)
(It is basically yield curve +/- some)
Rational behaviour of the normal investor Looking at the pile of cash behind
Fund puts limit pricing that balances requirement for attracting its investors and then buying the supply.
Burner Wallet & Vectis
Wallet address and sd-jwt can both be one use to minimise correlation.
Currently Vectis Factory only allows a wallet creator to deploy wallet contracts.
This is important because the process of KYC / AML is done when there is an account creation.
However, if we decouple this process of KYC / AML (and issuing a VC) to the user wallet, before an onchain account is created, then it is possible to allow users to create their own wallet if and only if they have the a valid credential presentation.
Oracle Providers
Platform-D Webapp Login with OID4VC to support multiple wallets
see Northern Block demo for more context. Use their wallet for best results
Sequence Diagram
sequenceDiagram
autonumber
participant Platform-D API (Gayadeed)
participant Platform-D Webapp
actor Vectis Wallet
participant Vectis API
participant Gayadeed API/DB
Note over Vectis Wallet: User Logged in (has Gayadeed token)
Platform-D Webapp ->> Vectis Wallet: Request VP on Vectis iframe
Vectis Wallet ->> Vectis Wallet: Approve request
Vectis Wallet ->> Vectis API: Request VP with Gayadeed token
Vectis API ->> Gayadeed API/DB: Request: VP with Gayadeed token
Gayadeed API/DB ->> Gayadeed API/DB: Derive VP
Gayadeed API/DB ->> Vectis API: Response: VP token with presentations
Vectis API ->> Vectis Wallet: VP token with presentations
Vectis Wallet ->> Platform-D Webapp: Response with VP token
Platform-D Webapp ->> Platform-D API (Gayadeed): Request to verify VP
Platform-D API (Gayadeed) ->> Platform-D Webapp: Approved and with token and user data
For step 2: Please see [Nortern Block demo] to show requested data
Verifier Request VP
Example QR code for requesting verifiable presentation:
openid-initiate-issuance://?
issuer=https://agent.openid4vci.nborbit.io
&credential_type=Gym Membership
&pre-authorized_code=
4688babc-5025-458a-91bb-b915c7a1d150.8068ef1d-07b7-4e30-8604-b4382489b272.d294fc0b-5ced-473d-8e03-a84e3be66e53