ldpos-client
Version:
JavaScript Client for LDPoS
946 lines (818 loc) • 30.8 kB
JavaScript
const SCAdapter = require('./sc-adapter');
const KeyManager = require('./key-manager');
const {
merkle,
generateWallet,
computePublicKeysFromPassphrase,
computeWalletAddressFromPassphrase,
computeWalletAddressFromPublicKey,
computeSeedFromPassphrase,
computePublicKeyFromSeed,
computeTreeFromSeed,
computeTreeName,
computeWalletAddressFromSeed,
computeTreeIndex,
computeLeafIndex,
computeId,
validatePassphrase,
validateWalletAddress,
getAllObjectKeySet,
getAllObjectKeys,
stringifyObject,
stringifyObjectWithMetadata,
sha256,
LEAF_COUNT,
SEED_ENCODING,
NODE_ENCODING,
SIGNATURE_ENCODING,
ID_ENCODING,
ID_LENGTH,
WALLET_ADDRESS_BASE_BYTE_LENGTH,
HEX_REGEX
} = require('./utils');
// TODO: Add methods for proving or disproving a signed transaction based on signatureHash.
class LDPoSClient {
constructor(options) {
this.options = options || {};
let { networkSymbol, verifyNetwork } = this.options;
this.networkSymbol = networkSymbol;
this.verifyNetwork = verifyNetwork == null ? true : verifyNetwork;
if (this.networkSymbol == null) {
throw new Error('A networkSymbol option must be specified when instantiating the client');
}
if (this.options.adapter) {
this.adapter = this.options.adapter;
} else {
if (
this.options.hostname == null ||
this.options.port == null
) {
throw new Error(
'If a custom adapter is not specified, then a hostname and port must be specified'
);
}
this.adapter = new SCAdapter(this.options);
}
if (this.options.keyManager) {
this.keyManager = this.options.keyManager;
} else {
this.keyManager = new KeyManager(this.options);
}
}
async connect(options) {
options = options || {};
if (this.adapter.connect) {
await this.adapter.connect();
}
if (this.verifyNetwork) {
this.verifyAdapterSupportsMethod('getNetworkSymbol');
let targetNetworkSymbol = await this.adapter.getNetworkSymbol();
if (targetNetworkSymbol !== this.networkSymbol) {
`The network symbol of the target node was different from that of the client; it was ${
targetNetworkSymbol
} but the client expected ${
this.networkSymbol
}`
}
}
if (!options.passphrase) {
return;
}
this.passphrase = options.passphrase;
this.seed = computeSeedFromPassphrase(this.passphrase);
this.sigPassphrase = this.passphrase;
this.sigSeed = this.seed;
if (options.multisigPassphrase) {
this.multisigPassphrase = options.multisigPassphrase;
this.multisigSeed = computeSeedFromPassphrase(this.multisigPassphrase);
} else {
this.multisigPassphrase = this.passphrase;
this.multisigSeed = this.seed;
}
if (options.forgingPassphrase) {
this.forgingPassphrase = options.forgingPassphrase;
this.forgingSeed = computeSeedFromPassphrase(this.forgingPassphrase);
} else {
this.forgingPassphrase = this.passphrase;
this.forgingSeed = this.seed;
}
if (options.walletAddress == null) {
this.walletAddress = await computeWalletAddressFromSeed(this.networkSymbol, this.sigSeed);
} else {
this.walletAddress = options.walletAddress;
}
if (options.forgingKeyIndex == null) {
this.forgingKeyIndex = await this.loadKeyIndex('forgingKeyIndex');
} else {
await this.saveKeyIndex('forgingKeyIndex', options.forgingKeyIndex);
this.forgingKeyIndex = options.forgingKeyIndex;
}
if (options.multisigKeyIndex == null) {
this.multisigKeyIndex = await this.loadKeyIndex('multisigKeyIndex');
} else {
await this.saveKeyIndex('multisigKeyIndex', options.multisigKeyIndex);
this.multisigKeyIndex = options.multisigKeyIndex;
}
if (options.sigKeyIndex == null) {
this.sigKeyIndex = await this.loadKeyIndex('sigKeyIndex');
} else {
await this.saveKeyIndex('sigKeyIndex', options.sigKeyIndex);
this.sigKeyIndex = options.sigKeyIndex;
}
await Promise.all([
this.makeForgingTreesFromKeyIndex(this.forgingKeyIndex),
this.makeMultisigTreesFromKeyIndex(this.multisigKeyIndex),
this.makeSigTreesFromKeyIndex(this.sigKeyIndex)
]);
}
disconnect() {
if (this.adapter.disconnect) {
this.adapter.disconnect();
}
}
async syncAllKeyIndexes() {
if (!this.passphrase) {
throw new Error(
'Client must be connected with a passphrase in order to sync key indexes'
);
}
let accountPromise = this.getAccount(this.walletAddress);
try {
let [ sig, multisig, forging ] = await Promise.all([
this.syncKeyIndex('sig', accountPromise),
this.syncKeyIndex('multisig', accountPromise),
this.syncKeyIndex('forging', accountPromise)
]);
return {
sig,
multisig,
forging
};
} catch (error) {
throw new Error(error.message);
}
}
capitalizeString(str) {
return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
}
async syncKeyIndex(type, sourceAccount) {
if (!this.passphrase) {
throw new Error(
'Client must be connected with a passphrase in order to sync a key index'
);
}
if (type !== 'forging' && type !== 'multisig' && type !== 'sig') {
throw new Error(`The ${type} key index type was invalid`);
}
let keyIndexName = `${type}KeyIndex`;
let [ account, storedKeyIndex ] = await Promise.all([
(async () => {
try {
return sourceAccount ? await sourceAccount : await this.getAccount(this.walletAddress);
} catch (error) {
if (error.name !== 'AccountDidNotExistError') {
throw error;
}
}
return null;
})(),
this.loadKeyIndex(keyIndexName)
]);
if (!account) {
return false;
}
let accountNextKeyIndexName = `next${this.capitalizeString(keyIndexName)}`;
let accountNextKeyIndex = account[accountNextKeyIndexName];
if (!Number.isInteger(accountNextKeyIndex) || accountNextKeyIndex < 1) {
return false;
}
let accountKeyIndex = accountNextKeyIndex - 1;
let publicKeyName = `${type}PublicKey`;
let accountPublicKey = account[publicKeyName];
let accountNextPublicKey = account[`next${this.capitalizeString(publicKeyName)}`];
let isKeyIndexValid = await this.verifyKeyIndex(type, accountKeyIndex, accountPublicKey, accountNextPublicKey);
if (!isKeyIndexValid) {
throw new Error(
`The target node sent back a key index which does not correspond to the ${
type
} public key of the account`
);
}
let isNew = accountKeyIndex > storedKeyIndex;
if (isNew) {
await this.saveKeyIndex(keyIndexName, accountKeyIndex);
if (type === 'forging') {
this.forgingKeyIndex = accountKeyIndex;
await this.makeForgingTreesFromKeyIndex(accountKeyIndex);
} else if (type === 'multisig') {
this.multisigKeyIndex = accountKeyIndex;
await this.makeMultisigTreesFromKeyIndex(accountKeyIndex);
} else {
this.sigKeyIndex = accountKeyIndex;
await this.makeSigTreesFromKeyIndex(accountKeyIndex);
}
}
return isNew;
}
async verifyKeyIndex(type, keyIndex, publicKey, nextPublicKey) {
if (!this.passphrase) {
throw new Error(
'Client must be connected with a passphrase in order to verify a key index'
);
}
if (type !== 'forging' && type !== 'multisig' && type !== 'sig') {
throw new Error(`The specified type was invalid`);
}
let seed = this[`${type}Seed`];
let treeIndex = computeTreeIndex(keyIndex);
let [ targetTree, targetNextTree ] = await Promise.all([
computeTreeFromSeed(this.networkSymbol, seed, type, treeIndex),
computeTreeFromSeed(this.networkSymbol, seed, type, treeIndex + 1)
]);
return publicKey === targetTree.publicRootHash && nextPublicKey === targetNextTree.publicRootHash;
}
async incrementKeyIndex(type) {
return this.keyManager.incrementKeyIndex(`${this.walletAddress}-${type}`);
}
async loadKeyIndex(type) {
return this.keyManager.loadKeyIndex(`${this.walletAddress}-${type}`);
}
async saveKeyIndex(type, value) {
return this.keyManager.saveKeyIndex(`${this.walletAddress}-${type}`, value);
}
async deleteKeyIndex(type) {
return this.keyManager.deleteKeyIndex(`${this.walletAddress}-${type}`);
}
async deleteAllKeyIndexes() {
try {
await Promise.all([
this.deleteKeyIndex('sigKeyIndex'),
this.deleteKeyIndex('multisigKeyIndex'),
this.deleteKeyIndex('forgingKeyIndex')
]);
} catch (error) {
throw new Error(error.message);
}
}
async generateWallet() {
return generateWallet(this.networkSymbol);
}
async computeWalletAddressFromPassphrase(passphrase) {
return computeWalletAddressFromPassphrase(this.networkSymbol, passphrase);
}
validatePassphrase(passphrase) {
return validatePassphrase(passphrase);
}
validateWalletAddress(walletAddress) {
return validateWalletAddress(this.networkSymbol, walletAddress);
}
sha256(message, encoding) {
return sha256(message, encoding);
}
getWalletAddress() {
if (!this.passphrase) {
throw new Error(
'Client must be connected with a passphrase in order to get the wallet address'
);
}
return this.walletAddress;
}
async prepareTransaction(transaction) {
if (!this.passphrase) {
throw new Error('Client must be connected with a passphrase in order to prepare a transaction');
}
let extendedTransaction = {
...transaction,
senderAddress: this.walletAddress
};
let transactionId = computeId(extendedTransaction);
await this.incrementSigKey();
extendedTransaction.sigPublicKey = this.sigTree.publicRootHash;
extendedTransaction.nextSigPublicKey = this.nextSigTree.publicRootHash;
extendedTransaction.nextSigKeyIndex = this.sigKeyIndex + 1;
extendedTransaction.id = transactionId;
let extendedTransactionWithIdJSON = stringifyObject(extendedTransaction);
let leafIndex = computeLeafIndex(this.sigKeyIndex);
let senderSignature = merkle.sign(extendedTransactionWithIdJSON, this.sigTree, leafIndex);
return {
...extendedTransaction,
senderSignature
};
}
async prepareTransfer(options) {
options = options || {};
let { recipientAddress, amount, fee } = options;
return this.prepareTransaction({
type: 'transfer',
recipientAddress,
amount,
fee,
timestamp: options.timestamp == null ? Date.now() : options.timestamp,
message: options.message == null ? '' : options.message
});
}
async prepareRegisterMultisigWallet(options) {
options = options || {};
let { memberAddresses, requiredSignatureCount, fee } = options;
return this.prepareTransaction({
type: 'registerMultisigWallet',
fee,
memberAddresses,
requiredSignatureCount,
timestamp: options.timestamp == null ? Date.now() : options.timestamp,
message: options.message == null ? '' : options.message
});
}
async prepareRegisterSigDetails(options) {
options = options || {};
let sigPassphrase = options.sigPassphrase || this.sigPassphrase;
let newNextSigKeyIndex = options.newNextSigKeyIndex || 0;
let treeIndex = computeTreeIndex(newNextSigKeyIndex);
let seed = computeSeedFromPassphrase(sigPassphrase);
let [ mssTree, nextMSSTree ] = await Promise.all([
computeTreeFromSeed(this.networkSymbol, seed, 'sig', treeIndex),
computeTreeFromSeed(this.networkSymbol, seed, 'sig', treeIndex + 1)
]);
return this.prepareTransaction({
type: 'registerSigDetails',
fee: options.fee,
newSigPublicKey: mssTree.publicRootHash,
newNextSigPublicKey: nextMSSTree.publicRootHash,
newNextSigKeyIndex,
timestamp: options.timestamp == null ? Date.now() : options.timestamp,
message: options.message == null ? '' : options.message
});
}
async prepareRegisterMultisigDetails(options) {
options = options || {};
let multisigPassphrase = options.multisigPassphrase || this.multisigPassphrase;
let newNextMultisigKeyIndex = options.newNextMultisigKeyIndex || 0;
let treeIndex = computeTreeIndex(newNextMultisigKeyIndex);
let seed = computeSeedFromPassphrase(multisigPassphrase);
let [ mssTree, nextMSSTree ] = await Promise.all([
computeTreeFromSeed(this.networkSymbol, seed, 'multisig', treeIndex),
computeTreeFromSeed(this.networkSymbol, seed, 'multisig', treeIndex + 1)
]);
return this.prepareTransaction({
type: 'registerMultisigDetails',
fee: options.fee,
newMultisigPublicKey: mssTree.publicRootHash,
newNextMultisigPublicKey: nextMSSTree.publicRootHash,
newNextMultisigKeyIndex,
timestamp: options.timestamp == null ? Date.now() : options.timestamp,
message: options.message == null ? '' : options.message
});
}
async prepareRegisterForgingDetails(options) {
options = options || {};
let forgingPassphrase = options.forgingPassphrase || this.forgingPassphrase;
let newNextForgingKeyIndex = options.newNextForgingKeyIndex || 0;
let treeIndex = computeTreeIndex(newNextForgingKeyIndex);
let seed = computeSeedFromPassphrase(forgingPassphrase);
let [ mssTree, nextMSSTree ] = await Promise.all([
computeTreeFromSeed(this.networkSymbol, seed, 'forging', treeIndex),
computeTreeFromSeed(this.networkSymbol, seed, 'forging', treeIndex + 1)
]);
return this.prepareTransaction({
type: 'registerForgingDetails',
fee: options.fee,
newForgingPublicKey: mssTree.publicRootHash,
newNextForgingPublicKey: nextMSSTree.publicRootHash,
newNextForgingKeyIndex,
timestamp: options.timestamp == null ? Date.now() : options.timestamp,
message: options.message == null ? '' : options.message
});
}
verifyTransactionId(transaction) {
let {
id,
senderSignature,
senderSignatureHash,
signatures,
sigPublicKey,
nextSigPublicKey,
nextSigKeyIndex,
...simplifiedTransaction
} = transaction;
let expectedId = computeId(simplifiedTransaction);
return id === expectedId;
}
verifyTransaction(transaction) {
if (!this.verifyTransactionId(transaction)) {
return false;
}
let { senderSignature, signatures, ...rawTransaction } = transaction;
let transactionJSON = stringifyObject(rawTransaction);
return merkle.verify(transactionJSON, senderSignature, transaction.sigPublicKey);
}
prepareMultisigTransaction(transaction) {
if (!this.passphrase && !transaction.senderAddress) {
throw new Error(
'Client must be connected with a passphrase in order to prepare a multisig transaction without specifying a senderAddress'
);
}
let extendedTransaction = {
...transaction,
senderAddress: transaction.senderAddress || this.walletAddress
};
extendedTransaction.id = computeId(extendedTransaction);
extendedTransaction.signatures = [];
return extendedTransaction;
}
async signMultisigTransaction(preparedTransaction) {
if (!this.passphrase) {
throw new Error('Client must be connected with a passphrase in order to sign a multisig transaction');
}
let { senderSignature, signatures, ...rawTransaction } = preparedTransaction;
await this.incrementMultisigKey();
let metaPacket = {
signerAddress: this.walletAddress,
multisigPublicKey: this.multisigTree.publicRootHash,
nextMultisigPublicKey: this.nextMultisigTree.publicRootHash,
nextMultisigKeyIndex: this.multisigKeyIndex + 1
};
let signablePacketJSON = stringifyObjectWithMetadata(rawTransaction, metaPacket);
let leafIndex = computeLeafIndex(this.multisigKeyIndex);
let signature = merkle.sign(signablePacketJSON, this.multisigTree, leafIndex);
return {
...metaPacket,
signature
};
}
attachMultisigTransactionSignature(preparedTransaction, signaturePacket) {
preparedTransaction.signatures.push(signaturePacket);
return preparedTransaction;
}
verifyMultisigTransactionSignature(transaction, signaturePacket) {
let { senderSignature, signatures, ...rawTransaction } = transaction;
let { signature, ...metaPacket } = signaturePacket;
let signablePacketJSON = stringifyObjectWithMetadata(rawTransaction, metaPacket);
return merkle.verify(signablePacketJSON, signature, metaPacket.multisigPublicKey);
}
async makeForgingTrees(treeIndex) {
let [ forgingTree, nextForgingTree ] = await Promise.all([
computeTreeFromSeed(this.networkSymbol, this.forgingSeed, 'forging', treeIndex),
computeTreeFromSeed(this.networkSymbol, this.forgingSeed, 'forging', treeIndex + 1)
]);
this.forgingTree = forgingTree;
this.forgingPublicKey = this.forgingTree.publicRootHash;
this.nextForgingTree = nextForgingTree;
this.nextForgingPublicKey = this.nextForgingTree.publicRootHash;
}
async makeForgingTreesFromKeyIndex(keyIndex) {
await this.makeForgingTrees(computeTreeIndex(keyIndex));
}
async incrementForgingKey() {
if (!this.passphrase) {
throw new Error(
'Client must be connected with a passphrase in order to increment the forging key'
);
}
let currentTreeIndex = computeTreeIndex(this.forgingKeyIndex);
this.forgingKeyIndex = await this.incrementKeyIndex('forgingKeyIndex');
let newTreeIndex = computeTreeIndex(this.forgingKeyIndex);
if (newTreeIndex !== currentTreeIndex) {
await this.makeForgingTrees(newTreeIndex);
}
}
async makeMultisigTrees(treeIndex) {
let [ multisigTree, nextMultisigTree ] = await Promise.all([
computeTreeFromSeed(this.networkSymbol, this.multisigSeed, 'multisig', treeIndex),
computeTreeFromSeed(this.networkSymbol, this.multisigSeed, 'multisig', treeIndex + 1)
]);
this.multisigTree = multisigTree;
this.multisigPublicKey = this.multisigTree.publicRootHash;
this.nextMultisigTree = nextMultisigTree;
this.nextMultisigPublicKey = this.nextMultisigTree.publicRootHash;
}
async makeMultisigTreesFromKeyIndex(keyIndex) {
await this.makeMultisigTrees(computeTreeIndex(keyIndex));
}
async incrementMultisigKey() {
if (!this.passphrase) {
throw new Error(
'Client must be connected with a passphrase in order to increment the multisig key'
);
}
let currentTreeIndex = computeTreeIndex(this.multisigKeyIndex);
this.multisigKeyIndex = await this.incrementKeyIndex('multisigKeyIndex');
let newTreeIndex = computeTreeIndex(this.multisigKeyIndex);
if (newTreeIndex !== currentTreeIndex) {
await this.makeMultisigTrees(newTreeIndex);
}
}
async makeSigTrees(treeIndex) {
let [ sigTree, nextSigTree ] = await Promise.all([
computeTreeFromSeed(this.networkSymbol, this.sigSeed, 'sig', treeIndex),
computeTreeFromSeed(this.networkSymbol, this.sigSeed, 'sig', treeIndex + 1)
]);
this.sigTree = sigTree;
this.sigPublicKey = this.sigTree.publicRootHash;
this.nextSigTree = nextSigTree;
this.nextSigPublicKey = this.nextSigTree.publicRootHash;
}
async makeSigTreesFromKeyIndex(keyIndex) {
await this.makeSigTrees(computeTreeIndex(keyIndex));
}
async incrementSigKey() {
if (!this.passphrase) {
throw new Error(
'Client must be connected with a passphrase in order to increment the sig key'
);
}
let currentTreeIndex = computeTreeIndex(this.sigKeyIndex);
this.sigKeyIndex = await this.incrementKeyIndex('sigKeyIndex');
let newTreeIndex = computeTreeIndex(this.sigKeyIndex);
if (newTreeIndex !== currentTreeIndex) {
await this.makeSigTrees(newTreeIndex);
}
}
async prepareBlock(block) {
if (!this.passphrase) {
throw new Error('Client must be connected with a passphrase in order to prepare a block');
}
let extendedBlock = {
...block,
forgerAddress: this.walletAddress
};
let blockId = computeId(extendedBlock);
await this.incrementForgingKey();
extendedBlock.forgingPublicKey = this.forgingTree.publicRootHash;
extendedBlock.nextForgingPublicKey = this.nextForgingTree.publicRootHash;
extendedBlock.nextForgingKeyIndex = this.forgingKeyIndex + 1;
extendedBlock.id = blockId;
let extendedBlockWithIdJSON = stringifyObject(extendedBlock);
let leafIndex = computeLeafIndex(this.forgingKeyIndex);
let forgerSignature = merkle.sign(extendedBlockWithIdJSON, this.forgingTree, leafIndex);
return {
...extendedBlock,
forgerSignature,
signatures: []
};
}
async signBlock(preparedBlock) {
if (!this.passphrase) {
throw new Error('Client must be connected with a passphrase in order to sign a block');
}
let { forgerSignature, signatures, ...rawBlock } = preparedBlock;
await this.incrementForgingKey();
let metaPacket = {
blockId: rawBlock.id,
signerAddress: this.walletAddress,
forgingPublicKey: this.forgingTree.publicRootHash,
nextForgingPublicKey: this.nextForgingTree.publicRootHash,
nextForgingKeyIndex: this.forgingKeyIndex + 1
};
let signablePacketJSON = stringifyObjectWithMetadata(rawBlock, metaPacket);
let leafIndex = computeLeafIndex(this.forgingKeyIndex);
let signature = merkle.sign(signablePacketJSON, this.forgingTree, leafIndex);
return {
...metaPacket,
signature
};
}
verifyBlockSignature(preparedBlock, signaturePacket) {
let { forgerSignature, signatures, ...rawBlock } = preparedBlock;
let { signature, ...metaPacket } = signaturePacket;
let signablePacketJSON = stringifyObjectWithMetadata(rawBlock, metaPacket);
return merkle.verify(signablePacketJSON, signature, metaPacket.forgingPublicKey);
}
verifyBlockId(block) {
let {
id,
forgerSignature,
signatures,
forgingPublicKey,
nextForgingPublicKey,
nextForgingKeyIndex,
...simplifiedBlock
} = block;
let expectedId = computeId(simplifiedBlock);
return id === expectedId;
}
verifyBlock(block) {
if (!this.verifyBlockId(block)) {
return false;
}
let { forgerSignature, signatures, ...rawBlock } = block;
let blockJSON = stringifyObject(rawBlock);
return merkle.verify(blockJSON, block.forgerSignature, block.forgingPublicKey);
}
async computeTree(type, treeIndex) {
let seed;
if (type === 'sig') {
seed = this.sigSeed;
} else if (type === 'multisig') {
seed = this.multisigSeed;
} else if (type === 'forging') {
seed = this.forgingSeed;
} else {
throw new Error(
`Tree type ${type} is invalid - It must be either sig, multisig or forging`
);
}
if (!seed) {
throw new Error(
`Client must be instantiated with a ${
type
} passphrase in order to compute an MSS tree of that type`
);
}
return computeTreeFromSeed(this.networkSymbol, seed, type, treeIndex);
}
signMessage(message, tree, leafIndex) {
return merkle.sign(message, tree, leafIndex);
}
verifyMessage(message, signature, publicRootHash) {
return merkle.verify(message, signature, publicRootHash);
}
async getPeers() {
this.verifyAdapterSupportsMethod('getPeers');
return this.adapter.getPeers();
}
async getNodeInfo() {
this.verifyAdapterSupportsMethod('getNodeInfo');
return this.adapter.getNodeInfo();
}
getNodeInfoChangeConsumer() {
this.verifyAdapterSupportsMethod('getNodeInfoChangeConsumer');
return this.adapter.getNodeInfoChangeConsumer();
}
async getNetworkSymbol() {
return this.networkSymbol;
}
async getChainInfo() {
this.verifyAdapterSupportsMethod('getChainInfo');
return this.adapter.getChainInfo();
}
async getAPIInfo() {
this.verifyAdapterSupportsMethod('getAPIInfo');
return this.adapter.getAPIInfo();
}
async getGenesis() {
this.verifyAdapterSupportsMethod('getGenesis');
return this.adapter.getGenesis();
}
async getAccount(walletAddress) {
this.verifyAdapterSupportsMethod('getAccount');
return this.adapter.getAccount(walletAddress);
}
async getAccountsByBalance(offset, limit, order) {
this.verifyAdapterSupportsMethod('getAccountsByBalance');
return this.adapter.getAccountsByBalance(offset, limit, order);
}
async getMultisigWalletMembers(walletAddress) {
this.verifyAdapterSupportsMethod('getMultisigWalletMembers');
return this.adapter.getMultisigWalletMembers(walletAddress);
}
async getSignedPendingTransaction(transactionId) {
this.verifyAdapterSupportsMethod('getSignedPendingTransaction');
return this.adapter.getSignedPendingTransaction(transactionId);
}
async getOutboundPendingTransactions(walletAddress, offset, limit) {
this.verifyAdapterSupportsMethod('getOutboundPendingTransactions');
return this.adapter.getOutboundPendingTransactions(walletAddress, offset, limit);
}
async getPendingTransactionCount() {
this.verifyAdapterSupportsMethod('getPendingTransactionCount');
return this.adapter.getPendingTransactionCount();
}
async postTransaction(preparedTransaction) {
this.verifyAdapterSupportsMethod('postTransaction');
return this.adapter.postTransaction(preparedTransaction);
}
async getTransaction(transactionId) {
this.verifyAdapterSupportsMethod('getTransaction');
return this.adapter.getTransaction(transactionId);
}
async getTransactionsByTimestamp(offset, limit, order) {
this.verifyAdapterSupportsMethod('getTransactionsByTimestamp');
return this.adapter.getTransactionsByTimestamp(offset, limit, order);
}
async getAccountTransactions(walletAddress, fromTimestamp, offset, limit, order) {
this.verifyAdapterSupportsMethod('getAccountTransactions');
return this.adapter.getAccountTransactions(walletAddress, fromTimestamp, offset, limit, order);
}
async getInboundTransactions(walletAddress, fromTimestamp, offset, limit, order) {
this.verifyAdapterSupportsMethod('getInboundTransactions');
return this.adapter.getInboundTransactions(walletAddress, fromTimestamp, offset, limit, order);
}
async getOutboundTransactions(walletAddress, fromTimestamp, offset, limit, order) {
this.verifyAdapterSupportsMethod('getOutboundTransactions');
return this.adapter.getOutboundTransactions(walletAddress, fromTimestamp, offset, limit, order);
}
async getTransactionsFromBlock(blockId, offset, limit) {
this.verifyAdapterSupportsMethod('getTransactionsFromBlock');
return this.adapter.getTransactionsFromBlock(blockId, offset, limit);
}
async getInboundTransactionsFromBlock(walletAddress, blockId) {
this.verifyAdapterSupportsMethod('getInboundTransactionsFromBlock');
return this.adapter.getInboundTransactionsFromBlock(walletAddress, blockId);
}
async getOutboundTransactionsFromBlock(walletAddress, blockId) {
this.verifyAdapterSupportsMethod('getOutboundTransactionsFromBlock');
return this.adapter.getOutboundTransactionsFromBlock(walletAddress, blockId);
}
async getLastBlockAtTimestamp(timestamp) {
this.verifyAdapterSupportsMethod('getLastBlockAtTimestamp');
return this.adapter.getLastBlockAtTimestamp(timestamp);
}
async getMaxBlockHeight() {
this.verifyAdapterSupportsMethod('getMaxBlockHeight');
return this.adapter.getMaxBlockHeight();
}
async getBlocksFromHeight(height, limit) {
this.verifyAdapterSupportsMethod('getBlocksFromHeight');
return this.adapter.getBlocksFromHeight(height, limit);
}
async getSignedBlocksFromHeight(height, limit) {
this.verifyAdapterSupportsMethod('getSignedBlocksFromHeight');
return this.adapter.getSignedBlocksFromHeight(height, limit);
}
async getBlocksBetweenHeights(fromHeight, toHeight, limit) {
this.verifyAdapterSupportsMethod('getBlocksBetweenHeights');
return this.adapter.getBlocksBetweenHeights(fromHeight, toHeight, limit);
}
async getBlockAtHeight(height) {
this.verifyAdapterSupportsMethod('getBlockAtHeight');
return this.adapter.getBlockAtHeight(height);
}
async getBlock(blockId) {
this.verifyAdapterSupportsMethod('getBlock');
return this.adapter.getBlock(blockId);
}
async getSignedBlock(blockId) {
this.verifyAdapterSupportsMethod('getSignedBlock');
return this.adapter.getSignedBlock(blockId);
}
async getBlocksByTimestamp(offset, limit, order) {
this.verifyAdapterSupportsMethod('getBlocksByTimestamp');
return this.adapter.getBlocksByTimestamp(offset, limit, order);
}
async getDelegatesByVoteWeight(offset, limit, order) {
this.verifyAdapterSupportsMethod('getDelegatesByVoteWeight');
return this.adapter.getDelegatesByVoteWeight(offset, limit, order);
}
async getForgingDelegates() {
this.verifyAdapterSupportsMethod('getForgingDelegates');
return this.adapter.getForgingDelegates();
}
async getDelegate(walletAddress) {
this.verifyAdapterSupportsMethod('getDelegate');
return this.adapter.getDelegate(walletAddress);
}
async getDelegateVoters(walletAddress, offset, limit, order) {
this.verifyAdapterSupportsMethod('getDelegateVoters');
return this.adapter.getDelegateVoters(walletAddress, offset, limit, order);
}
async getAccountVotes(walletAddress) {
this.verifyAdapterSupportsMethod('getAccountVotes');
return this.adapter.getAccountVotes(walletAddress);
}
async getMinFees() {
this.verifyAdapterSupportsMethod('getMinFees');
return this.adapter.getMinFees();
}
verifyAdapterSupportsMethod(methodName) {
if (!this.adapter[methodName]) {
throw new Error(
`Client adapter does not support the ${methodName} method`
);
}
}
}
function createClient(options) {
return new LDPoSClient(options);
}
module.exports = {
LDPoSClient,
createClient,
merkle,
generateWallet,
computePublicKeysFromPassphrase,
computeWalletAddressFromPassphrase,
computeWalletAddressFromPublicKey,
computeSeedFromPassphrase,
computePublicKeyFromSeed,
computeTreeFromSeed,
computeTreeName,
computeWalletAddressFromSeed,
computeTreeIndex,
computeLeafIndex,
computeId,
validatePassphrase,
validateWalletAddress,
getAllObjectKeySet,
getAllObjectKeys,
stringifyObject,
stringifyObjectWithMetadata,
sha256,
LEAF_COUNT,
SEED_ENCODING,
NODE_ENCODING,
SIGNATURE_ENCODING,
ID_ENCODING,
ID_LENGTH,
WALLET_ADDRESS_BASE_BYTE_LENGTH,
HEX_REGEX
};