apostille-library
Version:
A novel & holistic blockchain notarization and timestamping with transferable, updatable, branded, and conjointly owned notarizations.
280 lines • 14 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = require("lodash");
const nem2_sdk_1 = require("nem2-sdk");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const Errors_1 = require("../types/Errors");
const Initiator_1 = require("./Initiator");
const incompleteTransactionsFunc = (readyTransaction) => {
if (readyTransaction.initiator) {
return !readyTransaction.initiator.complete;
}
return true;
};
class ApostilleHttp {
constructor(url) {
this.announceList = [];
this.unannouncedTransactions = [];
this.transactionHttp = new nem2_sdk_1.TransactionHttp(url);
this.accountHttp = new nem2_sdk_1.AccountHttp(url);
this.blockHttp = new nem2_sdk_1.BlockHttp(url);
this.listener = new nem2_sdk_1.Listener(url);
}
static createLockFundsTransaction(signedAggregateBondedTransaction) {
const lockFundsTransaction = nem2_sdk_1.LockFundsTransaction.create(nem2_sdk_1.Deadline.create(), new nem2_sdk_1.Mosaic(new nem2_sdk_1.NamespaceId('nem.xem'), nem2_sdk_1.UInt64.fromUint(10)), nem2_sdk_1.UInt64.fromUint(480), signedAggregateBondedTransaction, signedAggregateBondedTransaction.networkType);
return lockFundsTransaction;
}
announce(signedTransaction) {
return new Promise((resolve, reject) => {
this.transactionHttp.announce(signedTransaction)
.subscribe((x) => resolve(x), (err) => reject(err));
});
}
announceAggregateBonded(cosignatoryAccount, signedAggregateBondedTransaction, signedLockFundsTransaction) {
return new Promise((resolve, reject) => {
this.listener.open().then(() => {
this.transactionHttp
.announce(signedLockFundsTransaction)
.subscribe((x) => console.log(x), (err) => reject(err));
this.listener
.confirmed(cosignatoryAccount.address)
.pipe(operators_1.filter((transaction) => {
return transaction.transactionInfo !== undefined
&& transaction.transactionInfo.hash === signedLockFundsTransaction.hash;
}), operators_1.mergeMap(() => this.transactionHttp.announceAggregateBonded(signedAggregateBondedTransaction)))
.subscribe((announcedAggregateBonded) => {
resolve(announcedAggregateBonded);
}, (err) => {
reject(err);
});
});
});
}
isCreated(publicAccount) {
return __awaiter(this, void 0, void 0, function* () {
try {
const unconfirmedTransactions = yield this._unconfirmedTransactions(publicAccount).toPromise();
if (unconfirmedTransactions.length > 0) {
return true;
}
else {
const transactions = yield this._transactions(publicAccount).toPromise();
return (transactions.length > 0);
}
}
catch (err) {
throw new Error(err);
}
});
}
getCosignatories(address) {
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
this.accountHttp.getMultisigAccountInfo(address).subscribe((multisigAccountInfo) => {
resolve(multisigAccountInfo.cosignatories);
}, (err) => reject(err));
}));
}
isOwned(address) {
return new Promise((resolve, reject) => {
this.getCosignatories(address).then((cosignatories) => {
resolve(cosignatories.length > 0);
}).catch((error) => {
const errorText = JSON.parse(error.response.text);
if (errorText.code === 'ResourceNotFound') {
resolve(false);
}
else {
reject(error);
}
});
});
}
getCreationTransactionInfo(publicAccount) {
return __awaiter(this, void 0, void 0, function* () {
try {
const transaction = yield this.getCreationTransaction(publicAccount);
if (transaction.transactionInfo instanceof nem2_sdk_1.TransactionInfo) {
return transaction.transactionInfo;
}
else {
throw new Error(Errors_1.Errors[Errors_1.Errors.TRANSACTION_INFO_NOT_FOUND]);
}
}
catch (error) {
throw new Error(error);
}
});
}
getCreationTransaction(publicAccount) {
return new Promise((resolve, reject) => {
this.fetchAllTransactions(publicAccount).pipe(operators_1.reduce((acc, txs) => {
return acc.concat(txs);
})).subscribe((transactions) => {
if (transactions.length > 0) {
const firstTransaction = transactions[transactions.length - 1];
if (firstTransaction instanceof nem2_sdk_1.TransferTransaction) {
resolve(firstTransaction);
}
else if (firstTransaction instanceof nem2_sdk_1.AggregateTransaction) {
const innerTransactions = firstTransaction.innerTransactions;
const sortedInnerTransactions = lodash_1.sortBy(innerTransactions, ['transactionInfo.index']);
for (let i = 0; i < sortedInnerTransactions.length; i++) {
const innerTransaction = sortedInnerTransactions[i];
if (innerTransaction.type === nem2_sdk_1.TransactionType.TRANSFER) {
resolve(innerTransaction);
}
}
}
}
reject(Errors_1.Errors[Errors_1.Errors.CREATION_TRANSACTIONS_NOT_FOUND]);
});
});
}
fetchAllTransactions(publicAccount) {
let nextId = '';
const pageSize = 100;
let lastPageSize = 100;
let queryParams = new nem2_sdk_1.QueryParams(pageSize);
return this._transactions(publicAccount, queryParams).pipe(operators_1.expand((transactions) => {
lastPageSize = transactions.length;
if (lastPageSize < pageSize) {
return rxjs_1.EMPTY;
}
nextId = transactions[transactions.length - 1].transactionInfo.id;
queryParams = new nem2_sdk_1.QueryParams(pageSize, nextId !== '' ? nextId : undefined);
return this._transactions(publicAccount, queryParams);
}), operators_1.shareReplay());
}
fetchAllTransactionsSync(publicAccount) {
return this.fetchAllTransactions(publicAccount).pipe(operators_1.reduce((acc, txs) => {
return acc.concat(txs);
})).toPromise();
}
_transactions(publicAccount, queryParams) {
return this.accountHttp.transactions(publicAccount, queryParams);
}
_unconfirmedTransactions(publicAccount, queryParams) {
return this.accountHttp.unconfirmedTransactions(publicAccount, queryParams);
}
addTransaction(readyTransaction) {
const { initiator } = readyTransaction;
if (initiator.canSign()) {
return this.unannouncedTransactions.push(readyTransaction);
}
else {
throw Error(Errors_1.Errors[Errors_1.Errors.INITIATOR_UNABLE_TO_SIGN]);
}
}
getIncompleteTransactions() {
return this.unannouncedTransactions.filter(incompleteTransactionsFunc);
}
hasIncompleteTransactions() {
return this.unannouncedTransactions.some(incompleteTransactionsFunc);
}
reduceInitiatorList(initiators) {
let allInitiators = [];
for (const i of initiators) {
if (i.account instanceof nem2_sdk_1.Account) {
allInitiators.push(i.account);
}
if (i.accountType === Initiator_1.initiatorAccountType.MULTISIG_ACCOUNT) {
allInitiators = allInitiators.concat(i.multiSigAccount.cosignatories);
}
}
return lodash_1.uniq(allInitiators);
}
aggregateAndSign(innerTransactions, generationHash) {
return lodash_1.chain(innerTransactions)
.chunk(1000)
.map((innerT) => {
const initiatorsArray = innerT.map((innerTransaction) => innerTransaction.initiator);
const innerTransactionsArray = innerT.map((innerTransaction) => innerTransaction.innerTransaction);
const allInitiators = this.reduceInitiatorList(initiatorsArray);
const [firstCosigner, ...cosigners] = allInitiators;
const aggregateTransaction = nem2_sdk_1.AggregateTransaction.createComplete(nem2_sdk_1.Deadline.create(), innerTransactionsArray, firstCosigner.address.networkType, []);
return firstCosigner.signTransactionWithCosignatories(aggregateTransaction, cosigners, generationHash);
}).value();
}
announceAll() {
return this.fetchGenerationHash().pipe(operators_1.first(), operators_1.concatMap((generationHash) => {
if (generationHash === '') {
throw new Error('generationHash cannot be empty!');
}
let innerTransactionsList = [];
let readyTx;
while (this.unannouncedTransactions.length > 0) {
readyTx = this.unannouncedTransactions.pop();
if (readyTx === undefined) {
break;
}
const { initiator, transaction } = readyTx;
if (transaction.type === nem2_sdk_1.TransactionType.TRANSFER ||
transaction.type === nem2_sdk_1.TransactionType.MODIFY_MULTISIG_ACCOUNT) {
if (initiator.complete) {
const refreshedTransaction = transaction.reapplyGiven(nem2_sdk_1.Deadline.create());
const innerTransaction = refreshedTransaction.toAggregate(initiator.publicAccount);
innerTransactionsList.push({ initiator, innerTransaction });
}
else {
this.announceList = this.announceList.concat(this.aggregateAndSign(innerTransactionsList, generationHash));
innerTransactionsList = [];
const aggregateBondedTransaction = initiator.sign(transaction, generationHash);
const lockFundsTransaction = ApostilleHttp.createLockFundsTransaction(aggregateBondedTransaction);
const signedLockFunds = initiator.sign(lockFundsTransaction, generationHash);
this.announceList.push(signedLockFunds);
this.announceList.push(aggregateBondedTransaction);
}
}
else if (transaction.type === nem2_sdk_1.TransactionType.AGGREGATE_BONDED ||
transaction.type === nem2_sdk_1.TransactionType.AGGREGATE_COMPLETE) {
this.announceList.concat(this.aggregateAndSign(innerTransactionsList, generationHash));
innerTransactionsList = [];
const signedTransaction = initiator.sign(transaction, generationHash);
this.announceList.push(signedTransaction);
}
}
this.announceList = this.announceList.concat(this.aggregateAndSign(innerTransactionsList, generationHash));
innerTransactionsList = [];
return rxjs_1.concat(rxjs_1.of(this.announceList), rxjs_1.from(this.announceList).pipe(operators_1.switchMap((signedTx) => {
return this.transactionHttp.announce(signedTx);
})), this.confirmedListener());
}));
}
fetchGenerationHash() {
return this.blockHttp.getBlockByHeight(1).pipe(operators_1.pluck('generationHash'));
}
confirmedListener() {
return rxjs_1.from(this.listener.open()).pipe(operators_1.switchMap(() => {
return this.listener.newBlock()
.pipe(operators_1.finalize(() => this.listener.close()), operators_1.takeWhile(() => this.announceList.length > 0), operators_1.switchMap(() => {
const transactionHashes = this.announceList.map((signedTx) => signedTx.hash);
return this.transactionHttp.getTransactionsStatuses(transactionHashes);
}), operators_1.map((txs) => {
for (const tx of txs) {
if (tx.group === 'confirmed') {
lodash_1.remove(this.announceList, (signedTx) => {
return signedTx.hash === tx.hash;
});
}
if (tx.group === 'failed') {
lodash_1.remove(this.announceList, (signedTx) => {
return signedTx.hash === tx.hash;
});
}
}
return txs;
}));
}));
}
}
exports.ApostilleHttp = ApostilleHttp;
//# sourceMappingURL=ApostilleHttp.js.map