@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
JavaScript
;
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