UNPKG

@ngraveio/ur-sync

Version:

Provides BC-UR types for syncing multiple coins and accounts from cold wallets to watch only wallets.

128 lines (123 loc) 6.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PortfolioCoin = void 0; const bc_ur_1 = require("@ngraveio/bc-ur"); const DetailedAccount_1 = require("./DetailedAccount"); const ur_coin_identity_1 = require("@ngraveio/ur-coin-identity"); const ur_blockchain_commons_1 = require("@ngraveio/ur-blockchain-commons"); class PortfolioCoin extends (0, bc_ur_1.registryItemFactory)({ tag: 41403, URType: 'portfolio-coin', keyMap: { coinId: 1, accounts: 2, masterFingerprint: 3, }, allowKeysNotInMap: false, CDDL: ` ; Associate a coin identity to its accounts detailed_accounts = [+ #6.41402(detailed-account)] ; The accounts are listed using #6.41402(detailed-account) to share the maximum of information related to the accounts coin = { coin-id: #6.41401(coin-identity), accounts: accounts_exp, ? master-fingerprint: uint32 ; Master fingerprint (fingerprint for the master public key as per BIP32) } ; master-fingerprint must match the potential other fingerprints included in the other sub-UR types coin-id = 1 accounts = 2 master-fingerprint = 3 `, }) { constructor(data) { super(data); // Legacy that supports CryptoAccount and CryptoMultiAccounts // // static checkInputs = (accounts: accounts_exp, masterFingerprint?: Uint8Array) => { // // if its detailed_accounts array, run CryptoDetailedAccount.checkAccount for each of them // if (Array.isArray(accounts)) { // accounts.forEach(account => { // // check if account is type of detailed account // // if not throw error // if (!(account instanceof DetailedAccount)) { // throw new Error('Account is not type of CryptoDetailedAccount') // } // // run checkAccount for each of the detailed account // DetailedAccount.checkAccount(account.getAccount()) // }) // } else if (accounts instanceof CryptoAccount) { // // Be sure that masterfingerprint is same as the one in CryptoAccount // if (masterFingerprint?.toString('hex') !== accounts.getMasterFingerprint().toString('hex')) { // throw new Error('Master fingerprint is not the same as the one in CryptoAccount') // } // // We will run checks on each of the CryptoOutput in CryptoAccount // accounts.getOutputDescriptors().forEach(output => { // DetailedAccount.checkAccount(output) // }) // } else if (accounts instanceof CryptoMultiAccounts) { // // Be sure that masterfingerprint is same as the one in CryptoMultiAccounts // if (masterFingerprint?.toString('hex') !== accounts.getMasterFingerprint().toString('hex')) { // throw new Error('Master fingerprint is not the same as the one in CryptoMultiAccounts') // } // // We will run checks on each of the CryptoAccount in CryptoMultiAccounts // accounts.getKeys().forEach(hdKey => { // DetailedAccount.checkAccount(hdKey) // }) // } // } this.getCoinId = () => this.data.coinId; this.getAccounts = () => this.data.accounts; // public getCryptoAccount = () => (this.accounts instanceof CryptoAccount ? this.accounts : undefined) // public getCryptoMultiAccounts = () => (this.accounts instanceof CryptoMultiAccounts ? this.accounts : undefined) this.getDetailedAccounts = () => this.data.accounts; this.getMasterFingerprint = () => this.data.masterFingerprint; this.data = data; } verifyInput(input) { const errors = []; // Type check if (input.coinId == undefined || !(input.coinId instanceof ur_coin_identity_1.CoinIdentity)) { errors.push(new Error('CoinId is not type of CoinIdentity')); } // Be sure that accounts is correct type if (input.accounts == undefined || !Array.isArray(input.accounts)) { errors.push(new Error('Accounts must be an array')); } // Check if accounts is an array of DetailedAccount input.accounts.forEach(account => { if (!(account instanceof DetailedAccount_1.DetailedAccount)) { errors.push(new Error('Account is not type of DetailedAccount')); } }); // If masterfingerprint is provided, make sure its valid uint32 number with clamped to max Unsigned 32-bit integer if (input.masterFingerprint !== undefined) { if (typeof input.masterFingerprint !== 'number' || input.masterFingerprint < 0 || input.masterFingerprint > 0xffffffff) { errors.push(new Error('Master fingerprint must be a valid uint32 number')); } } // If there are no errors yet do deep validation if (!errors.length) { // Edwards curve coins check each accounts origin paths and make sure they are all hardened if (input.coinId.getCurve() == ur_coin_identity_1.EllipticCurve.Ed25519) { input.accounts.forEach(account => { // For edwards curve coins we expect DetailedAccount to have HDKey as account if (!(account.getAccount() instanceof ur_blockchain_commons_1.HDKey)) { return { valid: false, reasons: [new Error('Ed25519 coin must have HDKey as account')] }; } // Check if HDKey has origin and all paths are hardened const hdKey = account.getAccount(); const origin = hdKey.getOrigin(); if (!origin?.isOnlyHardened()) { return { valid: false, reasons: [new Error('Ed25519 coin must have all hardened paths')] }; } }); } } return { valid: errors.length === 0, reasons: errors.length > 0 ? errors : undefined, }; } } exports.PortfolioCoin = PortfolioCoin; //# sourceMappingURL=PortfolioCoin.js.map