owned this note
owned this note
Published
Linked with GitHub
# Multi-Chain Account ID
In this document we define the Multi-chain account id. It is a compactly encoded account identifier that is blockchain agnostic.
```js
mcai ::= <multibase_prefix><mcai_code><chain_namespace><id_size><chain_id><address_size><address><parity_byte>
```
where,
* `multibase_prefix` - the prefix which defines which multibase is used to encode the bytes, `z` for `base58btc`
* `mcai_code` - a number registered on the [multicodec table](https://github.com/multiformats/multicodec/blob/master/table.csv), makes the multi-chain account id upgradable, encoded as varint
* `chain_namespace` - see table below, encoded as varint
* `id_size` - the length in bytes of the `chain_id`, encoded as varint
* `chain_id` - the chain id, encoding is defined by the chain namespace
* `address_size` - the length of the address, encoded as varint
* `address` - the address itself, encoding is defined by the chain namespace
* `parity_byte` - a checksum byte, see section below
## MCAI multicodec
Should be a number registered on the [multicodec table](https://github.com/multiformats/multicodec/blob/master/table.csv). In the examples below we use `0xCA` but this is subject to change.
## Chain namespaces
Each blockchain namespace needs to be properly defined.
### Registry table
| Namespace | code |
| -- | -- |
| bip122 | 0x00 |
| eip155 | 0x01 |
| cosmos | 0x02 |
| polkadot | 0x03 |
| filecoin | 0x04 |
### Bip122
**Chain ID:** Convert from hex to bytes
**Address:** Convert from base58btc to bytes
#### Example
In the exammple below we encode `128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6` on bitcoin mainnet.
This means that we use `chain_id = 000000000019d6689c085ae165831e93`
```
zEbYEtEFFMZvVzJK3AWU5R5egEj1ep1yMVEWiWJ2FARDz
```
### Eip155
**Chain ID:** Convert from integer to bytes
**Address:** Convert from hex to bytes
#### Example
In the exammple below we encode `0xde30da39c46104798bb5aa3fe8b9e0e1f348163f` on ethereum mainnet.
This means that we use `chain_id = 1`
```
zUJWDxUnc8pZCfUtVKcAsRgxijaVqHyuMgeKKF
```
### Cosmos
- TODO
### Polkadot
- TODO
### Filecoin
- TODO
## Parity byte
Using the algorithm described on [Wikipedia: checksums](https://en.wikipedia.org/wiki/Checksum). XOR each byte word in the mcai, the resulting byte is the parity byte.
## Making MCAI human readable
We could easily build tools and UIs that decompose the encoded mcai similar to this: https://cid.ipfs.io/#bagcqcera6wh5laey5njuo2weun46wv4cn2jlbn6qio6mt3bwian4kbp76tdq
## Implementation
Below is a PoC implementation in javascript
```js
const varint = require('varint')
const u8a = require('uint8arrays')
const mcai_code = 0xca
const namespaces = {
bip122: 0x00,
eip155: 0x01,
cosmos: 0x02,
polkadot: 0x03,
filecoin: 0x04
}
function checksum(bytes) {
let result = u8a.xor([bytes[0]], [bytes[1]])
for (let i = 2; i < bytes.length; i++) {
result = u8a.xor(result, [bytes[i]])
}
return result
}
function encodeMCAI(namespace, chain_id, address) {
const bytes = u8a.concat([
varint.encode(mcai_code),
Uint8Array.from([namespace]),
varint.encode(1), // chain_id below is just one byte
Uint8Array.from([chain_id]),
varint.encode(address.length),
address
])
const checksummedBytes = u8a.concat([bytes, checksum(bytes)])
return 'z' + u8a.toString(checksummedBytes, 'base58btc')
}
function encodeBtcMainnet() {
const chain_id = '000000000019d6689c085ae165831e93'
const chain_id_bytes = u8a.fromString(chain_id, 'base16')
const address = '128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6'
const address_bytes = u8a.fromString(address, 'base58btc')
return encodeMCAI(namespaces['bip122'], chain_id_bytes, address_bytes)
}
function encodeEthMainnet() {
const chain_id = 0x01
const address = '0xde30da39c46104798bb5aa3fe8b9e0e1f348163f'
const address_bytes = u8a.fromString(address.slice(2), 'base16')
return encodeMCAI(namespaces['eip155'], chain_id, address_bytes)
}
console.log('btc mainnet:', encodeBtcMainnet())
console.log('eth mainnet:', encodeEthMainnet())
```