@ngraveio/ur-sync
Version:
Provides BC-UR types for syncing multiple coins and accounts from cold wallets to watch only wallets.
172 lines (168 loc) • 7.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DetailedAccount = void 0;
const bc_ur_1 = require("@ngraveio/bc-ur");
const ur_blockchain_commons_1 = require("@ngraveio/ur-blockchain-commons");
const ur_hex_string_1 = require("@ngraveio/ur-hex-string");
class DetailedAccount extends (0, bc_ur_1.registryItemFactory)({
tag: 41402,
URType: 'detailed-account',
keyMap: {
account: 1,
tokenIds: 2,
},
allowKeysNotInMap: false,
CDDL: `
account_exp = #6.40303(hdkey) / #6.40308(output-descriptor)
; Accounts are specified using either '#6.40303(hdkey)' or
; '#6.40308(output-descriptor)'.
; By default, '#6.40303(hdkey)' should be used to share public keys and
; extended public keys.
; '#6.308(output-descriptor)' should be used to share an output descriptor,
; e.g. for the different Bitcoin address formats (P2PKH, P2SH-P2WPKH, P2WPKH, P2TR).
; Optional 'token-ids' to indicate the synchronization of a list of tokens with
; the associated accounts
; 'token-id' is defined differently depending on the blockchain:
; - ERC20 tokens on EVM chains are identified by their contract addresses
; (e.g. "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
; - ERC1155 tokens are identifed with their contract addresses followed by their
; ID with ':' as separator (e.g. "0xfaafdc07907ff5120a76b34b731b278c38d6043c:
; 508851954656174721695133294256171964208")
; - ESDT tokens on MultiversX are by their name followed by their ID with "-" as
; separator (e.g. "USDC-c76f1f")
; - SPL tokens on Solana are identified by their contract addresses
; (e.g. "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
detailed-account = {
account: account_exp,
? token-ids: [+ string / bytes] ; Specify multiple tokens associated to one account
}
account = 1
token-ids = 2
`,
}) {
constructor(data) {
// Token Ids are just hex string for erc20 token like 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
// For ESDT and SPL types its going to be encoded as string
// We will try to parse the string into bytes with removing 0x part,
// if we cannot we will encode it as utf8 string
super(data);
this.getAccount = () => this.data.account;
this.getHdKey = () => {
return this.data.account instanceof ur_blockchain_commons_1.HDKey ? this.data.account : undefined;
};
this.getOutputDescriptor = () => {
return this.data.account instanceof ur_blockchain_commons_1.OutputDescriptor ? this.data.account : undefined;
};
this.getTokenIds = () => {
if (!this.data.tokenIds)
return undefined;
// Always return string representation of the token ids
return this.data.tokenIds.map((tokenId) => {
if (tokenId instanceof ur_hex_string_1.HexString) {
// Shall we really add 0x to start?
return '0x' + tokenId.getData();
}
return tokenId;
});
};
//@ts-ignore
this.data = data;
let tokenIds = data.tokenIds;
// If token ids are provided, convert them to hex strings
if (tokenIds !== undefined && Array.isArray(data.tokenIds)) {
// Try to parse them into hex strings
tokenIds = tokenIds.map(tokenId => {
// If its already hexstring, return it
if (tokenId instanceof ur_hex_string_1.HexString)
return tokenId;
// If its buffer or a string try to parse as HexString
try {
return new ur_hex_string_1.HexString(tokenId);
}
catch (error) {
/* no-op */
return tokenId;
}
});
//@ts-ignore
this.data.tokenIds = tokenIds;
}
}
verifyInput(input) {
const errors = [];
// Checks for the accounts
if (!input.account) {
errors.push(new Error('Account must be provided'));
}
else {
try {
DetailedAccount.checkAccount(input.account);
}
catch (error) {
errors.push(error);
}
}
// Checks for the token ids
if (input.tokenIds !== undefined) {
// Token ids must be an array
if (!Array.isArray(input.tokenIds)) {
errors.push(new Error('Token ids must be an array'));
}
else {
// Token ids must be either string or uint8array (Buffer is also Uint8Array)
input.tokenIds.forEach(tokenId => {
if (typeof tokenId !== 'string' && !(tokenId instanceof Uint8Array) && !(tokenId instanceof ur_hex_string_1.HexString)) {
errors.push(new Error('Token id must be either a string or a Uint8Array or HexString'));
}
});
}
}
return {
valid: errors.length === 0,
reasons: errors.length > 0 ? errors : undefined,
};
}
static checkAccount(account) {
// If account is HDKey, check if it has origin and a valid path
if (account instanceof ur_blockchain_commons_1.HDKey) {
return DetailedAccount.checkHdKey(account);
}
else if (account instanceof ur_blockchain_commons_1.OutputDescriptor) {
return DetailedAccount.checkOutputDescriptor(account);
}
else {
throw new Error('Account must be instance of HDKey or OutputDescriptor');
}
return true;
}
static checkOutputDescriptor(account) {
// For the output descriptor, it must have only 1 key and it must be HDKey
const keys = account.data.keys;
if (!keys || keys.length !== 1) {
throw new Error('Output descriptor must have only 1 key');
}
const key = keys[0];
if (!(key instanceof ur_blockchain_commons_1.HDKey)) {
throw new Error('Output descriptor key must be instance of HDKey');
}
// Check HDKey properties
return DetailedAccount.checkHdKey(key);
}
static checkHdKey(hdKey) {
const origin = hdKey.getOrigin();
if (origin == undefined) {
throw new Error('HDKey must have origin');
}
// Now for detailed account we must have only 1 path
// and it should only contain simple path components
// Eg: m/44'/60'/0
// The other path components are not allowed
// Eg: m/44/*/1-5
if (!origin.isOnlySimple()) {
throw new Error('Detailed account path can only contain index components');
}
return true;
}
}
exports.DetailedAccount = DetailedAccount;
//# sourceMappingURL=DetailedAccount.js.map