Multi Layer Sync Protocol
This is the implementation of the Multi Layer Sync Protocol that supports multiple coins and accounts with different types via globally identifiable URs.
This package add support for following ur types:
Type | [CBOR Tag] | Owner | Description | Definition |
---|
crypto-detailed-account | 1402 | Ngrave | Import multiple accounts with and without output descriptors and specify optionally tokens to synchronize | [NBCR-2023-002] |
crypto-portfolio-coin | 1403 | Ngrave | Associate several accounts to its coin identity | [NBCR-2023-002] |
crypto-portfolio | 1405 | Ngrave | Aggregate the portfolio information | [NBCR-2023-002] |
This repository is an extension of bc-ur-registry
Installing
To install, run:
yarn add @ngraveio/bc-ur-multi-layer-sync
npm install --save @ngraveio/bc-ur-multi-layer-sync
Examples:
CryptoDetailedAccount
[CryptoDetailedAccount] Construct a crypto detailed account with hdkey.
const originKeyPath = new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 501, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
])
const cryptoHDKey = new CryptoHDKey({
isMaster: false,
key: Buffer.from('02eae4b876a8696134b868f88cc2f51f715f2dbedb7446b8e6edf3d4541c4eb67b', 'hex'),
origin: originKeyPath,
})
const detailedAccount = new CryptoDetailedAccount(cryptoHDKey)
const cbor = detailedAccount.toCBOR().toString('hex')
const ur = detailedAccount.toUREncoder(1000).nextPart()
console.log(cbor)
console.log(ur)
[CryptoDetailedAccount] Decode a crypto detailed account with hdkey.
const cbor =
'a101d9012fa203582102eae4b876a8696134b868f88cc2f51f715f2dbedb7446b8e6edf3d4541c4eb67b06d90130a10188182cf51901f5f500f500f5';
const detailedAccount = CryptoDetailedAccount.fromCBOR(Buffer.from(cbor, 'hex'));
const hdKey = detailedAccount.getAccount() as CryptoHDKey;
[CryptoDetailedAccount] Construct a crypto detailed account with CryptoOutput p2pkh hdkey.
const scriptExpressions = [ScriptExpressions.PUBLIC_KEY_HASH]
const originKeypath = new CryptoKeypath(
[new PathComponent({ index: 44, hardened: true }), new PathComponent({ index: 0, hardened: true }), new PathComponent({ index: 0, hardened: true })],
Buffer.from('d34db33f', 'hex')
)
const childrenKeypath = new CryptoKeypath([new PathComponent({ index: 1, hardened: false }), new PathComponent({ hardened: false })])
const hdkey = new CryptoHDKey({
isMaster: false,
key: Buffer.from('02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0', 'hex'),
chainCode: Buffer.from('637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29', 'hex'),
origin: originKeypath,
children: childrenKeypath,
parentFingerprint: Buffer.from('78412e3a', 'hex'),
})
const cryptoOutput = new CryptoOutput(scriptExpressions, hdkey)
const detailedAccount = new CryptoDetailedAccount(cryptoOutput)
const cbor = detailedAccount.toCBOR().toString('hex')
console.log(cbor)
const ur = detailedAccount.toUREncoder(1000).nextPart()
console.log(ur)
[CryptoDetailedAccount] Decode a crypto detailed account with CryptoOutput p2pkh hdkey.
const cbor =
'a101d90134d90193d9012fa503582102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0045820637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e2906d90130a20186182cf500f500f5021ad34db33f07d90130a1018401f480f4081a78412e3a';
const detailedAccount = CryptoDetailedAccount.fromCBOR(Buffer.from(cbor, 'hex'));
const cryptoOutput = detailedAccount.getAccount() as CryptoOutput;
[CryptoPortfolioCoin] create CryptoPortfolioCoin with 2 detailed accounts with tokens
const coinIdentity = new CryptoCoinIdentity(EllipticCurve.secp256k1, 60)
const cryptoHDKey = new CryptoHDKey({
isMaster: false,
key: Buffer.from('02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0', 'hex'),
origin: new CryptoKeypath([
new PathComponent({ index: 60, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: false }),
new PathComponent({ index: 0, hardened: false }),
]),
parentFingerprint: Buffer.from('78412e3a', 'hex'),
})
const tokenIds = ['0xdac17f958d2ee523a2206206994597c13d831ec7', '0xB8c77482e45F1F44dE1745F52C74426C631bDD52']
const cryptoHDKey2 = CryptoHDKey.fromCBOR(
Buffer.from('a203582102eae4b876a8696134b868f88cc2f51f715f2dbedb7446b8e6edf3d4541c4eb67b06d90130a10188182cf51901f5f500f500f5', 'hex')
)
const tokenIds2 = ['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v']
const detailedAccount = new CryptoDetailedAccount(cryptoHDKey, tokenIds)
const detailedAccount2 = new CryptoDetailedAccount(cryptoHDKey2, tokenIds2)
const cryptoPortfolioCoin = new CryptoPortfolioCoin(coinIdentity, [detailedAccount, detailedAccount2])
const cbor = cryptoPortfolioCoin.toCBOR().toString('hex')
console.log(cbor)
const ur = cryptoPortfolioCoin.toUREncoder(1000).nextPart()
console.log(ur)
[CryptoPortfolioCoin] Decode the CryptoPortfolioCoin with 2 detailed accounts with tokens
const cryptoPortfolioCoin = CryptoPortfolioCoin.fromCBOR(Buffer.from(cbor, 'hex'))
const coinID = cryptoPortfolioCoin.getCoinId()
const accounts = cryptoPortfolioCoin.getAccounts()
[CryptoPortfolio] create a CryptoPortfolio with 4 coins and Metadata
const coinIdEth = new CryptoCoinIdentity(EllipticCurve.secp256k1, 60)
const coinIdSol = new CryptoCoinIdentity(EllipticCurve.secp256k1, 501)
const coinIdMatic = new CryptoCoinIdentity(EllipticCurve.secp256k1, 60, [137])
const coinIdBtc = new CryptoCoinIdentity(EllipticCurve.secp256k1, 0)
const accountEth = new CryptoDetailedAccount(
new CryptoHDKey({
isMaster: false,
key: Buffer.from('032503D7DCA4FF0594F0404D56188542A18D8E0784443134C716178BC1819C3DD4', 'hex'),
chainCode: Buffer.from('D2B36900396C9282FA14628566582F206A5DD0BCC8D5E892611806CAFB0301F0', 'hex'),
origin: new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 60, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
]),
children: new CryptoKeypath([new PathComponent({ index: 0, hardened: false }), new PathComponent({ index: 1, hardened: false })]),
}),
['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48']
)
const accountMatic = new CryptoDetailedAccount(
new CryptoHDKey({
isMaster: false,
key: Buffer.from('032503D7DCA4FF0594F0404D56188542A18D8E0784443134C716178BC1819C3DD4', 'hex'),
chainCode: Buffer.from('D2B36900396C9282FA14628566582F206A5DD0BCC8D5E892611806CAFB0301F0', 'hex'),
origin: new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 60, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
]),
children: new CryptoKeypath([new PathComponent({ index: 0, hardened: false }), new PathComponent({ index: 1, hardened: false })]),
}),
['2791Bca1f2de4661ED88A30C99A7a9449Aa84174']
)
const accountSol = new CryptoDetailedAccount(
new CryptoHDKey({
isMaster: false,
key: Buffer.from('02EAE4B876A8696134B868F88CC2F51F715F2DBEDB7446B8E6EDF3D4541C4EB67B', 'hex'),
origin: new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 501, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
]),
}),
['EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v']
)
const accountBtc = new CryptoDetailedAccount(
new CryptoOutput(
[ScriptExpressions.PUBLIC_KEY_HASH],
new CryptoHDKey({
isMaster: false,
key: Buffer.from('03EB3E2863911826374DE86C231A4B76F0B89DFA174AFB78D7F478199884D9DD32', 'hex'),
chainCode: Buffer.from('6456A5DF2DB0F6D9AF72B2A1AF4B25F45200ED6FCC29C3440B311D4796B70B5B', 'hex'),
origin: new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
]),
children: new CryptoKeypath([new PathComponent({ index: 0, hardened: false }), new PathComponent({ index: 0, hardened: false })]),
})
)
)
const cryptoCoinEth = new CryptoPortfolioCoin(coinIdEth, [accountEth])
const cryptoCoinSol = new CryptoPortfolioCoin(coinIdSol, [accountSol])
const cryptoCoinMatic = new CryptoPortfolioCoin(coinIdMatic, [accountMatic])
const cryptoCoinBtc = new CryptoPortfolioCoin(coinIdBtc, [accountBtc])
const metadata = new CryptoPortfolioMetadata({
sync_id: Buffer.from('123456781234567802D9044FA3011A71', 'hex'),
language_code: 'en',
fw_version: '1.2.1-1.rc',
device: 'NGRAVE ZERO',
})
const cryptoPortfolio = new CryptoPortfolio([cryptoCoinEth, cryptoCoinSol, cryptoCoinMatic, cryptoCoinBtc], metadata)
const cbor = cryptoPortfolio.toCBOR().toString('hex')
const ur = cryptoPortfolio.toUREncoder(1000).nextPart()
[CryptoPortfolio] Decode the cryptoPortfolio.
const cryptoPortfolio = CryptoPortfolio.fromCBOR(Buffer.from(cbor, 'hex'))
const metadata = decodedCryptoPortfolio.getMetadata()
const coins = cryptoPortfolio.getCoins()
const accounts = coins[0]?.getDetailedAccounts()