-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
97 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,146 @@ | ||
[![](.maintain/media/kilt-header.png)](https://kilt.io) | ||
|
||
# KiltTransferAssetRecipientV1 | ||
# KiltTransferAssetRecipientV2 | ||
|
||
### Editors | ||
|
||
- **Antonio Antonino** - KILT Protocol [[email protected]](mailto:[email protected]) | ||
- **Albrecht Weiche** - KILT Protocol [[email protected]](mailto:[email protected]) | ||
|
||
--- | ||
|
||
## Abstract | ||
|
||
This document defines an extension to the service types supported in the [DID Core W3C spec][did-core-spec] by defining the `KiltTransferAssetRecipientV1` service type. | ||
This document defines an extension to the service types supported in the [DID Core W3C spec][did-core-spec] by defining the `KiltTransferAssetRecipientV2` service type. | ||
The goal of the endpoints of this class is to expose a collection (i.e., a list) of addresses to which assets of some class can be sent to. | ||
For more information about the KILT DID method, please visit our [official specification][kilt-did-spec]. | ||
|
||
## Data structure | ||
## Data Structure | ||
|
||
A service endpoint of type `KiltTransferAssetRecipientV1` does not include any additional properties compared to what is defined within the [relative section of the official DID Core spec][did-core-spec-services]. | ||
A service endpoint of type `KiltTransferAssetRecipientV2` does not include any additional properties compared to what is defined within the [relative section of the official DID Core spec][did-core-spec-services]. | ||
Furthermore, endpoints of such type MUST include at least *one* URI for the `serviceEndpoint` property. | ||
Each of the URIs in `serviceEndpoint`, when dereferenced, MUST return **a JSON containing an object** with a mapping from each type of asset to the list of accounts the DID subject controls for that asset, optionally with a description of each account. | ||
Each of the URIs in `serviceEndpoint`, when dereferenced, MUST return **a JSON object** with a mapping from each type of asset to the list of accounts the DID subject controls for that asset, optionally with a description of each account. | ||
An example of the object described is given below. | ||
|
||
```json | ||
{ | ||
"polkadot:411f057b9107718c9624d6aa4a3f23c1/slip44:2086": [ | ||
{ | ||
"account": "4qBSZdEoUxPVnUqbX8fjXovgtQXcHK7ZvSf56527XcDZUukq", | ||
"description": "Treasury proposals transfers" | ||
}, | ||
{ | ||
"account": "4oHvgA54py7SWFPpBCoubAajYrxj6xyc8yzHiAVryeAq574G", | ||
"description": "Regular transfers" | ||
"polkadot:b0a8d493285c2df73290dfb7e61f870f/slip44:434": { | ||
"EJDj2GKnx89HTzUkGW8Rk9RoYUmAJHPM8aacWFp3fi1gYUQ": { | ||
"description": "Personal account" | ||
} | ||
}, | ||
"polkadot:411f057b9107718c9624d6aa4a3f23c1/slip44:2086": { | ||
"4nvZhWv71x8reD9gq7BUGYQQVvTiThnLpTTanyru9XckaeWa": { | ||
"description": "Council account" | ||
}, | ||
{ | ||
"account": "4taHgf8x9U5b8oJaiYoNEh61jaHpKs9caUdattxfBRkJMHvm" | ||
"4tMSjvHfWBNQw4tYGvkbRp7BBpwAB6S24LuMDcASYgnGnRTM" : { | ||
"description": "Personal account" | ||
} | ||
], | ||
"eip:1/slip44:60": [ | ||
{ | ||
"account": "0x8f8221AFBB33998D8584A2B05749BA73C37A938A", | ||
}, | ||
"polkadot:91b171bb158e2d3848fa23a9f1c25182/slip44:354": { | ||
"15BQbTH5bKH63WCXTMPxbmpnWeXKpfuTKbpDkfFLXMPvpxD3": { | ||
"description": "Personal account" | ||
} | ||
}, | ||
"eip:1/slip44:60": { | ||
"0x6b175474e89094c44da98b954eedeac495271d0f": {}, | ||
"0x8f8221AFBB33998D8584A2B05749BA73C37A938A": { | ||
"description": "NFT sales" | ||
}, | ||
{ | ||
"account": "0x6b175474e89094c44da98b954eedeac495271d0f" | ||
} | ||
] | ||
} | ||
} | ||
``` | ||
|
||
Each asset is identified by its [CAIP-19 identifier][caip-19-spec]. | ||
The value of the property for each asset MUST be a set of accounts encoded according to the chain rules. | ||
For example, for Spiritnet accounts, the account is the base58-prefixed encoding of the Spiritnet chain ID + the account public key. | ||
For Ethereum accounts, it's the 20-byte HEX representation of the account public key, prefixed with `0x`. | ||
Other chains have different encoding rules for accounts, and each chain defines the format and encoding logic for public keys representing accounts on those chains. | ||
The value of the property for each asset MUST be another object with the following structure: | ||
|
||
Hence, the example above shows a `KiltTransferAssetRecipientV1` endpoint indicating other parties that the DID subject can accept transfers of the following two assets: | ||
* One key for each `account` that can receive assets of the specified type. The account MUST be encoded according to the rules of the chain on which the asset lives. For example, for Spiritnet accounts, the account is the base58-prefixed encoding of the Spiritnet chain ID + the account public key. For Ethereum accounts, it's the 20-byte HEX representation of the account public key, prefixed with `0x`. Other chains have different encoding rules for accounts, and each chain defines the format and encoding logic for public keys representing accounts on those chains. | ||
* For each account, an object with the following properties: | ||
* [OPTIONAL] `description`: The user-provided description for the specified account. | ||
|
||
- *KILT Spiritnet tokens* sent to either of the addresses `4qBSZdEoUxPVnUqbX8fjXovgtQXcHK7ZvSf56527XcDZUukq`, `4oHvgA54py7SWFPpBCoubAajYrxj6xyc8yzHiAVryeAq574G`, or `4taHgf8x9U5b8oJaiYoNEh61jaHpKs9caUdattxfBRkJMHvm` on the Spiritnet parachain. | ||
- *Ether tokens* sent to either of the addresses `0x8f8221AFBB33998D8584A2B05749BA73C37A938A`, or `0x6b175474e89094c44da98b954eedeac495271d0f` on the Ethereum mainnet. | ||
The example above shows a `KiltTransferAssetRecipientV2` endpoint indicating other parties that the DID subject can accept transfers of the following four assets: | ||
|
||
The `id` property of the endpoint MUST be the [multibase][multibase] representation of the Blake256 output calculated from the Base64 encoding of the resource dereferenced by the URIs in `serviceEndpoint`. | ||
The multibase chosen must yield values that do not contain invalid characters as per the definition of the `id` property in the DID specification, i.e., the resulting `id` must still be a valid URI conforming to [RFC3986][rfc3986]. | ||
- *DOT tokens* sent to the address `15BQbTH5bKH63WCXTMPxbmpnWeXKpfuTKbpDkfFLXMPvpxD3` on the Polkadot relaychain. | ||
- *KILT Spiritnet tokens* sent to either of the addresses `4tMSjvHfWBNQw4tYGvkbRp7BBpwAB6S24LuMDcASYgnGnRTM`, or `4nvZhWv71x8reD9gq7BUGYQQVvTiThnLpTTanyru9XckaeWa` on the KILT Spiritnet parachain. | ||
- *KSM tokens* sent to the address `EJDj2GKnx89HTzUkGW8Rk9RoYUmAJHPM8aacWFp3fi1gYUQ` on the Kusama relaychain. | ||
- *ETH non-fungible tokens* sent to the either of the addresses `0x6b175474e89094c44da98b954eedeac495271d0f`, or `0x8f8221AFBB33998D8584A2B05749BA73C37A938A` on the Ethereum mainnet. | ||
|
||
Hence, calling `M` the multibase encoding operation of some data, `H` the Blake256 hashing, and `B` the binary representation of some information, the service `id` for a given object `O` is `M(H(B(O)))`. | ||
### Object Canonicalization and Hashing | ||
|
||
The `id` property of the endpoint MUST be the [multibase][multibase] representation of the Blake2b-256 output calculated from the Base64 encoding of the [canonical representation][rfc8785] of the resource dereferenced by the URIs in `serviceEndpoint`. | ||
The multibase chosen MUST yield values that do not contain invalid characters as per the definition of the `id` property in the DID specification, i.e., the resulting `id` MUST still be a valid URI conforming to [RFC3986][rfc3986]. | ||
|
||
The retrieved resource MUST be canonicalized before being hashed, according to the [RFC 8785 specification][rfc8785]. | ||
This canonicalization step is required to ensure that two semantically-equivalent services do not hash to two different values. | ||
|
||
Hence, calling `M` the multibase encoding operation of some data, `H` the Blake2b-256 hashing, `B` the binary representation of some information, and `N` the canonicalization step, the service `id` for a given object `O` is `M(H(B(N(O))))`. | ||
For example, with the object `O` being the example `serviceEndpoint` shown above, and the multibase `M` being `base64urlpad`, the resulting service endpoint looks like the following: | ||
|
||
```json | ||
{ | ||
"id": "did:kilt:4pqDzaWi3w7TzYzGnQDyrasK6UnyNnW6JQvWRrq6r8HzNNGy#Uc1JU0UF9iDfjaRkgHCFG2Rc5jki-cuhlgbEQcjN6-g0=", | ||
"id": "did:kilt:4pqDzaWi3w7TzYzGnQDyrasK6UnyNnW6JQvWRrq6r8HzNNGy#Uif4uWQYSXeeMLAQPNX2aEJvMEmHGkvEqcL-zZdKkRhM=", | ||
"type": [ | ||
"KiltTransferAssetRecipientV1" | ||
"KiltTransferAssetRecipientV2" | ||
], | ||
"serviceEndpoint": [ | ||
"https://ipfs.io/ipfs/QmfLCY7Jxa4rRhpQ1FK3srtyM6C5ZLk4YmXfS7nm4Ur2GG" | ||
"https://gist.githubusercontent.com/ntn-x2/375d047e6be61d243b9cf645bc94a436/raw/f41c9f4976e09a29e6bd63f84eabdcd0f6cf2f4d/KiltTransferAssetRecipientV2-example.json" | ||
] | ||
} | ||
``` | ||
|
||
## Security considerations | ||
A Typescript snippet showing how to derive the service ID for the example document above is shown below: | ||
|
||
```ts | ||
import { blake2AsU8a } from '@polkadot/util-crypto' | ||
import * as multibase from 'multibase' | ||
import canonicalize from 'canonicalize' | ||
|
||
const doc = ` | ||
{ | ||
"polkadot:b0a8d493285c2df73290dfb7e61f870f/slip44:434": { | ||
"EJDj2GKnx89HTzUkGW8Rk9RoYUmAJHPM8aacWFp3fi1gYUQ": { | ||
"description": "Personal account" | ||
} | ||
}, | ||
"polkadot:411f057b9107718c9624d6aa4a3f23c1/slip44:2086": { | ||
"4nvZhWv71x8reD9gq7BUGYQQVvTiThnLpTTanyru9XckaeWa": { | ||
"description": "Council account" | ||
}, | ||
"4tMSjvHfWBNQw4tYGvkbRp7BBpwAB6S24LuMDcASYgnGnRTM" : { | ||
"description": "Personal account" | ||
} | ||
}, | ||
"polkadot:91b171bb158e2d3848fa23a9f1c25182/slip44:354": { | ||
"15BQbTH5bKH63WCXTMPxbmpnWeXKpfuTKbpDkfFLXMPvpxD3": { | ||
"description": "Personal account" | ||
} | ||
}, | ||
"eip:1/slip44:60": { | ||
"0x6b175474e89094c44da98b954eedeac495271d0f": {}, | ||
"0x8f8221AFBB33998D8584A2B05749BA73C37A938A": { | ||
"description": "NFT sales" | ||
} | ||
} | ||
} | ||
` | ||
|
||
function main() { | ||
const jsonInput = JSON.parse(doc) | ||
const canonicalJson = canonicalize(jsonInput) | ||
const buffer = Buffer.from(canonicalJson as any) | ||
const hash = blake2AsU8a(buffer) | ||
const encoded = multibase.encode('base64urlpad', hash) | ||
console.log(Buffer.from(encoded).toString('utf-8')) | ||
} | ||
|
||
main() | ||
``` | ||
|
||
## Security Considerations | ||
|
||
The list of addresses where the DID owner wants to receive funds must always be under the subject's control even if stored off-chain. | ||
The list of addresses where the DID owner wants to receive funds MUST always be under the subject's control even if stored off-chain. | ||
This ensures the authenticity and integrity of the list. | ||
Implementations must verify that the list of addresses retrieved from the service URI can be hashed and encoded to the same value as the service `id`. | ||
Failure to verify this condition MUST be treated as an attack either towards the DID subject or the entity willing to initiate the asset transfer, and the operation must be aborted. | ||
Implementations MUST verify that the list of addresses retrieved from the service URI can be hashed and encoded to the same value as the service `id` after following the canonicalization and hashing steps outlined above. | ||
Failure to verify this condition MUST be treated as an attack either towards the DID subject or the entity willing to initiate the asset transfer, and the operation MUST be aborted. | ||
|
||
[did-core-spec]: https://www.w3.org/TR/did-core | ||
[kilt-did-spec]: https://github.com/KILTprotocol/spec-kilt-did | ||
|