From bcbd3831b705dee67a024a7001e1fae21d17455d Mon Sep 17 00:00:00 2001 From: Jonathan Tey Date: Tue, 27 Nov 2018 12:28:47 +0800 Subject: [PATCH 1/5] fix(ApostillePublicAccount): Fix transfer not removing previous owners --- src/model/apostille/ApostillePublicAccount.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/apostille/ApostillePublicAccount.ts b/src/model/apostille/ApostillePublicAccount.ts index 894c0b8..433ed6e 100644 --- a/src/model/apostille/ApostillePublicAccount.ts +++ b/src/model/apostille/ApostillePublicAccount.ts @@ -58,7 +58,7 @@ export class ApostillePublicAccount { cosignatory)); }); - newOwners.forEach((cosignatory) => { + ownersToRemove.forEach((cosignatory) => { modifications.push( new MultisigCosignatoryModification( MultisigCosignatoryModificationType.Remove, From 0b09e2d3ae91a69a725f1a9911235161e62b5868 Mon Sep 17 00:00:00 2001 From: Jonathan Tey Date: Tue, 27 Nov 2018 14:29:54 +0800 Subject: [PATCH 2/5] docs: Update inline jsDocs --- src/infrastructure/ApostilleHttp.ts | 424 +++++++++--------- src/model/apostille/Apostille.ts | 19 +- src/model/apostille/ApostillePublicAccount.ts | 371 +++++++-------- src/model/apostille/PublicApostille.ts | 5 +- src/model/repository/HistoricalEndpoints.ts | 2 +- src/model/repository/Sinks.ts | 2 +- src/types/Errors.ts | 2 + 7 files changed, 417 insertions(+), 408 deletions(-) diff --git a/src/infrastructure/ApostilleHttp.ts b/src/infrastructure/ApostilleHttp.ts index 1c7e6df..16c7714 100644 --- a/src/infrastructure/ApostilleHttp.ts +++ b/src/infrastructure/ApostilleHttp.ts @@ -5,225 +5,225 @@ import { Errors } from '../types/Errors'; export class ApostilleHttp { - private transactionHttp: TransactionHttp; - private accountHttp: AccountHttp; - - public constructor(url: string) { - this.transactionHttp = new TransactionHttp(url); - this.accountHttp = new AccountHttp(url); - } - - public announce(signedTransaction: SignedTransaction): Promise { - return new Promise((resolve, reject) => { - this.transactionHttp.announce(signedTransaction) - .subscribe((x) => resolve(x), (err) => reject(err)); - }); - } - - public announceAggregateBonded( - cosignatoryAccount: PublicAccount, - signedAggregateBondedTransaction: SignedTransaction, - signedLockFundsTransaction: SignedTransaction, - listener: Listener): void { - - listener.open().then(() => { - - this.transactionHttp - .announce(signedLockFundsTransaction) - .subscribe((x) => console.log(x), (err) => console.error(err)); - - listener - .confirmed(cosignatoryAccount.address) - .pipe( - filter((transaction) => transaction.transactionInfo !== undefined - && transaction.transactionInfo.hash === signedLockFundsTransaction.hash), - mergeMap((ignored) => this.transactionHttp.announceAggregateBonded( - signedAggregateBondedTransaction)), - ) - .subscribe((announcedAggregateBonded) => console.log(announcedAggregateBonded), - (err) => console.error(err)); - }); - } - - /** - * @description - cheks on chain if there are any transactions announced - * @returns {Promise} - * @memberof ApostilleAccount - */ - public async isCreated(publicAccount: PublicAccount): Promise { - try { - const unconfirmedTransactions = await this._unconfirmedTransactions(publicAccount); - if (unconfirmedTransactions.length) { - // the apostille has been sent to the network - return true; - } else { - // then check transactions - const transactions = await this._transactions(publicAccount); - if (transactions.length) { - return true; - } else { - return true; - } - } - } catch (err) { - throw new Error(err); + private transactionHttp: TransactionHttp; + private accountHttp: AccountHttp; + + public constructor(url: string) { + this.transactionHttp = new TransactionHttp(url); + this.accountHttp = new AccountHttp(url); + } + + public announce(signedTransaction: SignedTransaction): Promise { + return new Promise((resolve, reject) => { + this.transactionHttp.announce(signedTransaction) + .subscribe((x) => resolve(x), (err) => reject(err)); + }); + } + + public announceAggregateBonded( + cosignatoryAccount: PublicAccount, + signedAggregateBondedTransaction: SignedTransaction, + signedLockFundsTransaction: SignedTransaction, + listener: Listener): void { + + listener.open().then(() => { + + this.transactionHttp + .announce(signedLockFundsTransaction) + .subscribe((x) => console.log(x), (err) => console.error(err)); + + listener + .confirmed(cosignatoryAccount.address) + .pipe( + filter((transaction) => transaction.transactionInfo !== undefined + && transaction.transactionInfo.hash === signedLockFundsTransaction.hash), + mergeMap((ignored) => this.transactionHttp.announceAggregateBonded( + signedAggregateBondedTransaction)), + ) + .subscribe((announcedAggregateBonded) => console.log(announcedAggregateBonded), + (err) => console.error(err)); + }); + } + + /** + * @description - cheks on chain if there are any transactions announced + * @returns {Promise} + * @memberof ApostilleAccount + */ + public async isCreated(publicAccount: PublicAccount): Promise { + try { + const unconfirmedTransactions = await this._unconfirmedTransactions(publicAccount); + if (unconfirmedTransactions.length) { + // the apostille has been sent to the network + return true; + } else { + // then check transactions + const transactions = await this._transactions(publicAccount); + if (transactions.length) { + return true; + } else { + return true; } + } + } catch (err) { + throw new Error(err); } - - /** - * @description - get cosignatories of the account - * @returns {Promise} - * @memberof ApostilleHttp - */ - public getCosignatories(address: Address): Promise { - return new Promise(async (resolve, reject) => { - this.accountHttp.getMultisigAccountInfo(address).subscribe( - (multisigAccountInfo) => { - resolve(multisigAccountInfo.cosignatories); - }, - (err) => reject(err), - ); - }); + } + + /** + * @description - get cosignatories of the account + * @returns {Promise} + * @memberof ApostilleHttp + */ + public getCosignatories(address: Address): Promise { + return new Promise(async (resolve, reject) => { + this.accountHttp.getMultisigAccountInfo(address).subscribe( + (multisigAccountInfo) => { + resolve(multisigAccountInfo.cosignatories); + }, + (err) => reject(err), + ); + }); + } + + /** + * @description - get first transaction + * @static + * @returns {Promise} + * @memberof ApostilleHttp + */ + public async isOwned(address: Address): Promise { + try { + const cossignatories = await this.getCosignatories(address); + if (cossignatories.length > 0) { + return true; + } else { + return false; + } + } catch (error) { + const errorText = JSON.parse(error.response.text); + if (errorText.code === 'ResourceNotFound') { + return false; + } else { + throw new Error(error); + } } - - /** - * @description - get first transaction - * @static - * @returns {Promise} - * @memberof ApostilleHttp - */ - public async isOwned(address: Address): Promise { - try { - const cossignatories = await this.getCosignatories(address); - if (cossignatories.length > 0) { - return true; - } else { - return false; - } - } catch (error) { - const errorText = JSON.parse(error.response.text); - if (errorText.code === 'ResourceNotFound') { - return false; - } else { - throw new Error(error); - } - } + } + + /** + * @description - get creationTransaction Info + * @param {string} urls + * @returns {Promise} + * @memberof ApostilleAccount + */ + public async getCreationTransactionInfo(publicAccount: PublicAccount): Promise { + try { + const transaction: TransferTransaction = await this.getCreationTransaction(publicAccount); + if (transaction.transactionInfo instanceof TransactionInfo) { + return transaction.transactionInfo; + } else { + throw new Error(Errors[Errors.TRANSACTION_INFO_NOT_FOUND]); + } + } catch (error) { + throw new Error(error); } - - /** - * @description - get creationTransaction Info - * @param {string} urls - * @returns {Promise} - * @memberof ApostilleAccount - */ - public async getCreationTransactionInfo(publicAccount: PublicAccount): Promise { - try { - const transaction: TransferTransaction = await this.getCreationTransaction(publicAccount); - if (transaction.transactionInfo instanceof TransactionInfo) { - return transaction.transactionInfo; + } + + /** + * @description - get first transaction + * @param {string} urls + * @returns {Promise} + * @memberof ApostilleAccount + */ + public getCreationTransaction(publicAccount: PublicAccount): Promise { + return new Promise((resolve, reject) => { + this._fetchAllTransactions(publicAccount).then((transactions: Transaction[]) => { + if (transactions.length > 0) { + const firstTransaction = transactions[transactions.length - 1]; + if (firstTransaction instanceof TransferTransaction) { + resolve (firstTransaction); + } else if (firstTransaction instanceof AggregateTransaction) { + // if the smallest index is aggregate transaction, then sort it by index + const innerTransactions = firstTransaction.innerTransactions; + const sortedInnerTransactions = sortBy( + innerTransactions, ['transactionInfo.index']); + const firstInnerTransaction = sortedInnerTransactions[0]; + if (firstInnerTransaction instanceof TransferTransaction) { + resolve (firstInnerTransaction); } else { - throw new Error(Errors[Errors.TRANSACTION_INFO_NOT_FOUND]); + reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); } - } catch (error) { - throw new Error(error); + } else { + reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); + } + } else { + reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); } - } - - /** - * @description - get first transaction - * @param {string} urls - * @returns {Promise} - * @memberof ApostilleAccount - */ - public getCreationTransaction(publicAccount: PublicAccount): Promise { - return new Promise((resolve, reject) => { - this._fetchAllTransactions(publicAccount).then((transactions: Transaction[]) => { - if (transactions.length > 0) { - const firstTransaction = transactions[transactions.length - 1]; - if (firstTransaction instanceof TransferTransaction) { - resolve (firstTransaction); - } else if (firstTransaction instanceof AggregateTransaction) { - // if the smallest index is aggregate transaction, then sort it by index - const innerTransactions = firstTransaction.innerTransactions; - const sortedInnerTransactions = sortBy( - innerTransactions, ['transactionInfo.index']); - const firstInnerTransaction = sortedInnerTransactions[0]; - if (firstInnerTransaction instanceof TransferTransaction) { - resolve (firstInnerTransaction); - } else { - reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); - } - } else { - reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); - } - } else { - reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); - } - }); + }); + }); + } + + /** + * Fetch all transactions pertaining to this publicAccount + * + * @returns {Promise} + * @memberof CertificateHistory + */ + public _fetchAllTransactions(publicAccount: PublicAccount): Promise { + return new Promise(async (resolve, reject) => { + let nextId: string = ''; + const pageSize: number = 100; + let lastPageSize: number = 100; + const allTransactions: Transaction[] = []; + while (lastPageSize === pageSize) { + const queryParams = new QueryParams(pageSize, nextId !== '' ? nextId : undefined); + await this._transactions(publicAccount, queryParams).then((transactions) => { + lastPageSize = transactions.length; + if (lastPageSize < 1) { return; } + nextId = transactions[transactions.length - 1].transactionInfo!.id; + allTransactions.push(...transactions); + }).catch((err) => { + reject(err); }); - } - - /** - * Fetch all transactions pertaining to this publicAccount - * - * @returns {Promise} - * @memberof CertificateHistory - */ - public _fetchAllTransactions(publicAccount: PublicAccount): Promise { - return new Promise(async (resolve, reject) => { - let nextId: string = ''; - const pageSize: number = 100; - let lastPageSize: number = 100; - const allTransactions: Transaction[] = []; - while (lastPageSize === pageSize) { - const queryParams = new QueryParams(pageSize, nextId !== '' ? nextId : undefined); - await this._transactions(publicAccount, queryParams).then((transactions) => { - lastPageSize = transactions.length; - if (lastPageSize < 1) { return; } - nextId = transactions[transactions.length - 1].transactionInfo!.id; - allTransactions.push(...transactions); - }).catch((err) => { - reject(err); - }); - } - resolve(allTransactions); - }); - } - - private _unconfirmedTransactions( - publicAccount: PublicAccount, - queryParams?: QueryParams | undefined): Promise { - - return new Promise((resolve, reject) => { - this.accountHttp.unconfirmedTransactions( - publicAccount, - queryParams, - ).subscribe((unconfirmedTransactions) => { - resolve(unconfirmedTransactions); - }, (err) => { - // network or comunication problem - resolve(err); - }); - }); - - } - - private _transactions( - publicAccount: PublicAccount, - queryParams?: QueryParams | undefined): Promise { - - return new Promise((resolve, reject) => { - this.accountHttp.transactions( - publicAccount, - queryParams, - ).subscribe((transactions) => { - resolve(transactions); - }, (err) => { - // network or comunication problem - resolve(err); - }); - }); - - } + } + resolve(allTransactions); + }); + } + + private _unconfirmedTransactions( + publicAccount: PublicAccount, + queryParams?: QueryParams | undefined): Promise { + + return new Promise((resolve, reject) => { + this.accountHttp.unconfirmedTransactions( + publicAccount, + queryParams, + ).subscribe((unconfirmedTransactions) => { + resolve(unconfirmedTransactions); + }, (err) => { + // network or comunication problem + resolve(err); + }); + }); + + } + + private _transactions( + publicAccount: PublicAccount, + queryParams?: QueryParams | undefined): Promise { + + return new Promise((resolve, reject) => { + this.accountHttp.transactions( + publicAccount, + queryParams, + ).subscribe((transactions) => { + resolve(transactions); + }, (err) => { + // network or comunication problem + resolve(err); + }); + }); + + } } diff --git a/src/model/apostille/Apostille.ts b/src/model/apostille/Apostille.ts index 5fcda95..108315d 100644 --- a/src/model/apostille/Apostille.ts +++ b/src/model/apostille/Apostille.ts @@ -14,6 +14,7 @@ const fixPrivateKey = (privateKey) => { * @class Apostille */ export class Apostille { + /** * @description init apostille * @static @@ -41,6 +42,8 @@ export class Apostille { return new Apostille(hdAccount); } + private publicAccount; + /** * Creates an instance of Apostille. * @param {Account} hdAccount - the apostille account (HD account) @@ -49,13 +52,17 @@ export class Apostille { */ public constructor( public readonly HDAccount: Account, - ) {} + ) { + this.publicAccount = new ApostillePublicAccount(this.HDAccount.publicAccount); + } /** + * * @description - create a multisig contract to own the apostille account - * @param {PublicAccount[]} owners - array of public account that will become owners + * @param {PublicAccount[]} owners- array of public account that will become owners * @param {number} quorum - the minimum number of owners necessary to agree on the apostille account activities * @param {number} minRemoval - minimum number of owners necessary to agree to remove one or some owners + * @returns {SignedTransaction} * @memberof Apostille */ public associate(owners: PublicAccount[], quorum: number, minRemoval: number): SignedTransaction { @@ -66,7 +73,7 @@ export class Apostille { MultisigCosignatoryModificationType.Add, cosignatory)); }); - const convertIntoMultisigTransaction = ModifyMultisigAccountTransaction.create( + const modifyMultisigTransaction = ModifyMultisigAccountTransaction.create( Deadline.create(), quorum, minRemoval, @@ -74,13 +81,13 @@ export class Apostille { this.HDAccount.address.networkType, ); - const signedTransaction = this.HDAccount.sign(convertIntoMultisigTransaction); + const signedTransaction = this.HDAccount.sign(modifyMultisigTransaction); - return signedTransaction; + return signedTransaction; } get apostillePublicAccount(): ApostillePublicAccount { - return new ApostillePublicAccount(this.HDAccount.publicAccount); + return this.publicAccount; } } diff --git a/src/model/apostille/ApostillePublicAccount.ts b/src/model/apostille/ApostillePublicAccount.ts index 433ed6e..e85503c 100644 --- a/src/model/apostille/ApostillePublicAccount.ts +++ b/src/model/apostille/ApostillePublicAccount.ts @@ -1,203 +1,204 @@ -import { drop } from 'lodash'; import { Account, AggregateTransaction, Deadline, LockFundsTransaction, ModifyMultisigAccountTransaction, Mosaic, MultisigCosignatoryModification, MultisigCosignatoryModificationType, PlainMessage, PublicAccount, SignedTransaction, Transaction, TransferTransaction, UInt64, XEM } from 'nem2-sdk'; import { HashFunction } from '../../hash/HashFunction'; import { Errors } from '../../types/Errors'; export class ApostillePublicAccount { - /** - * @param {PublicAccount} publicAccount - */ - constructor(public readonly publicAccount: PublicAccount) { + /** + * @param {PublicAccount} publicAccount + * @memberof ApostillePublicAccount + */ + constructor(public readonly publicAccount: PublicAccount) { + } + + /** + * @description - returning a transfer transaction for the apostille account + * @param {string} rawData - the raw data to send in the payload + * @param {(Mosaic[] | Mosaic[])} [mosaics=[]] - array of mosiacs to attach + * @returns {TransferTransaction} + * @memberof ApostillePublicAccount + */ + public update( + rawData: string, + mosaics: Mosaic[] = [], + ): TransferTransaction { + const plainMessage = PlainMessage.create(rawData); + + const creationTransaction = TransferTransaction.create( + Deadline.create(), + this.publicAccount.address, + mosaics, + plainMessage, + this.publicAccount.address.networkType, + ); + + return creationTransaction; + } + + /** + * @description - modify ownership of the apostille account by modifying the multisig contract + * @param {PublicAccount[]} newOwners - array of owners to add + * @param {PublicAccount[]} OwnersToRemove - array of owners to remove + * @param {number} quorum - relative quorum (refer to http://bit.ly/2Jnff1r) + * @param {number} minRemoval - relative number of minimum owners necessary to agree to remove 1/n owners + * @returns {ModifyMultisigAccountTransaction} + * @memberof ApostilleAccount + */ + public transfer( + newOwners: PublicAccount[], + ownersToRemove: PublicAccount[], + quorum: number, + minRemoval: number, + ): ModifyMultisigAccountTransaction { + // the initiator must be a multisig account + const modifications: MultisigCosignatoryModification[] = []; + newOwners.forEach((cosignatory) => { + modifications.push( + new MultisigCosignatoryModification( + MultisigCosignatoryModificationType.Add, + cosignatory)); + }); + + ownersToRemove.forEach((cosignatory) => { + modifications.push( + new MultisigCosignatoryModification( + MultisigCosignatoryModificationType.Remove, + cosignatory)); + }); + + const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create( + Deadline.create(), + quorum, + minRemoval, + modifications, + this.publicAccount.address.networkType, + ); + + return modifyMultisigAccountTransaction; + } + + /** + * @description creates a lockfunds transaction for an aggregate bonded transaction + * @param {SignedTransaction} signedAggregateBondedTransaction + * @returns {LockFundsTransaction} + * @memberof ApostillePublicAccount + */ + public lockFundsTransaction(signedAggregateBondedTransaction: SignedTransaction): LockFundsTransaction { + const lockFundsTransaction = LockFundsTransaction.create( + Deadline.create(), + XEM.createRelative(10), + UInt64.fromUint(480), + signedAggregateBondedTransaction, + this.publicAccount.address.networkType); + + return lockFundsTransaction; + } + + /** + * @description sign normal transaction (can sign update(if normal transaction) and lockFundsTransaction) + * @param {TransferTransaction} transferTransaction + * @param {Account} initiatorAccount + * @param {HashFunction} [hashFunction] - only hash transfer transaction message + * @returns + * @memberof ApostillePublicAccount + */ + public sign( + transaction: TransferTransaction | Transaction, + initiatorAccount: Account, + hashFunction?: HashFunction) { + if (initiatorAccount.address.networkType !== this.publicAccount.address.networkType) { + throw new Error(Errors[Errors.NETWORK_TYPE_MISMATCHED]); } - /** - * @description - returning a transfer transaction for the apostille account - * @param {string} rawData - the raw data to send in the payload - * @param {(Mosaic[] | Mosaic[])} [mosaics=[]] - array of mosiacs to attache - * @returns {TransferTransaction} - * @memberof ApostillePublicAccount - */ - public update( - rawData: string, - mosaics: Mosaic[] | Mosaic[] = [], - ): TransferTransaction { - const plainMessage = PlainMessage.create(rawData); - - const creationTransaction = TransferTransaction.create( - Deadline.create(), - this.publicAccount.address, - mosaics, - plainMessage, - this.publicAccount.address.networkType, - ); - - return creationTransaction; - } + let tx = transaction; - /** - * @description - modify ownership of the apostille account by modifying the multisisg contratc - * @param {PublicAccount[]} newOwners - array of new owners - * @param {PublicAccount[]} OwnersToRemove - array of owners to remove - * @param {number} quorum - relative quorum (refer to own function above and/or http://bit.ly/2Jnff1r ) - * @param {number} minRemoval - relative number of minimum owners necessary to agree to remove 1/n owners - * @returns {ModifyMultisigAccountTransaction} - * @memberof ApostilleAccount - */ - public transfer( - newOwners: PublicAccount[], - ownersToRemove: PublicAccount[], - quorum: number, - minRemoval: number, - ): ModifyMultisigAccountTransaction { - // the initiator must be a multisig account - const modifications: MultisigCosignatoryModification[] = []; - newOwners.forEach((cosignatory) => { - modifications.push( - new MultisigCosignatoryModification( - MultisigCosignatoryModificationType.Add, - cosignatory)); - }); - - ownersToRemove.forEach((cosignatory) => { - modifications.push( - new MultisigCosignatoryModification( - MultisigCosignatoryModificationType.Remove, - cosignatory)); - }); - - const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create( - Deadline.create(), - quorum, - minRemoval, - modifications, - this.publicAccount.address.networkType, - ); - - return modifyMultisigAccountTransaction; - } + // first we create the creation transaction as a transfer transaction + if (hashFunction && tx instanceof TransferTransaction) { + // for digital files it's a good idea to hash the content of the file + // but can be used for other types of information for real life assets - /** - * @description returning lockFundTransactions that can be signed later on - * @param {SignedTransaction} signedAggregateBondedTransaction - * @returns {LockFundsTransaction} - * @memberof ApostillePublicAccount - */ - public lockFundsTransaction(signedAggregateBondedTransaction: SignedTransaction): LockFundsTransaction { - const lockFundsTransaction = LockFundsTransaction.create( - Deadline.create(), - XEM.createRelative(10), - UInt64.fromUint(480), - signedAggregateBondedTransaction, - this.publicAccount.address.networkType); - - return lockFundsTransaction; - } + const rawData = tx.message.payload; - /** - * @description sign normal transaction (can sign update(if normal transaction) and lockFundsTransaction) - * @param {TransferTransaction} transferTransaction - * @param {Account} initiatorAccount - * @param {HashFunction} [hashFunction] - only hash transfer transaction message - * @returns - * @memberof ApostillePublicAccount - */ - public sign( - transaction: TransferTransaction | Transaction, - initiatorAccount: Account, - hashFunction?: HashFunction) { - if (initiatorAccount.address.networkType !== this.publicAccount.address.networkType) { - throw new Error(Errors[Errors.NETWORK_TYPE_MISMATCHED]); - } - - let tx = transaction; - - // first we create the creation transaction as a transfer transaction - if (hashFunction && tx instanceof TransferTransaction) { - // for digital files it's a good idea to hash the content of the file - // but can be used for other types of information for real life assets - - const rawData = tx.message.payload; - - const hash = hashFunction.signedHashing( - rawData, - initiatorAccount.privateKey, - this.publicAccount.address.networkType, - ); - - tx = this.update(hash, tx.mosaics); - } - - const signedTransaction = initiatorAccount.sign(tx); - - return signedTransaction; - } + const hash = hashFunction.signedHashing( + rawData, + initiatorAccount.privateKey, + this.publicAccount.address.networkType, + ); - /** - * @description signed aggregate transaction (can sign update(if multisig transaction) and transfer transaction) - * @param {Transaction} transaction - * @param {Account[]} signers - * @param {boolean} isCompleteCosignatories - * @returns - * @memberof ApostillePublicAccount - */ - public signAggregate(transaction: Transaction, signers: Account[], isCompleteCosignatories: boolean) { - if (isCompleteCosignatories) { - return this._signTransferTransactionAgregateComplete(transaction, signers); - } else { - return this._signTransferTransactionAggregateBonded(transaction, signers); - } + tx = this.update(hash, tx.mosaics); } - private _signTransferTransactionAgregateComplete( - transaction: Transaction, - signers: Account[], - ): SignedTransaction { - const aggregateTransaction = AggregateTransaction.createComplete( - Deadline.create(), - [transaction.toAggregate(this.publicAccount)], - this.publicAccount.address.networkType, - []); - - const signedAggregateTransaction = this._signAggregate(aggregateTransaction, signers); - - return signedAggregateTransaction; + const signedTransaction = initiatorAccount.sign(tx); + + return signedTransaction; + } + + /** + * @description signed aggregate transaction (can sign update(if multisig transaction) and transfer transaction) + * @param {Transaction} transaction + * @param {Account[]} signers + * @param {boolean} isCompleteCosignatories + * @returns + * @memberof ApostillePublicAccount + */ + public signAggregate(transaction: Transaction, signers: Account[], isCompleteCosignatories: boolean) { + if (isCompleteCosignatories) { + return this._signTransferTransactionAgregateComplete(transaction, signers); + } else { + return this._signTransferTransactionAggregateBonded(transaction, signers); } - - private _signTransferTransactionAggregateBonded( - transaction: Transaction, - signers: Account[], - ): SignedTransaction { - const aggregateTransaction = AggregateTransaction.createBonded( - Deadline.create(), - [transaction.toAggregate(this.publicAccount)], - this.publicAccount.address.networkType); - - const signedAggregateTransaction = this._signAggregate(aggregateTransaction, signers); - - return signedAggregateTransaction; + } + + private _signTransferTransactionAgregateComplete( + transaction: Transaction, + signers: Account[], + ): SignedTransaction { + const aggregateTransaction = AggregateTransaction.createComplete( + Deadline.create(), + [transaction.toAggregate(this.publicAccount)], + this.publicAccount.address.networkType, + []); + + const signedAggregateTransaction = this._signAggregate(aggregateTransaction, signers); + + return signedAggregateTransaction; + } + + private _signTransferTransactionAggregateBonded( + transaction: Transaction, + signers: Account[], + ): SignedTransaction { + const aggregateTransaction = AggregateTransaction.createBonded( + Deadline.create(), + [transaction.toAggregate(this.publicAccount)], + this.publicAccount.address.networkType); + + const signedAggregateTransaction = this._signAggregate(aggregateTransaction, signers); + + return signedAggregateTransaction; + } + + private _signAggregate(aggregateTransaction: AggregateTransaction, signers: Account[]): SignedTransaction { + // fetch the first signer + const mainSigner = signers.shift(); + + if (mainSigner === undefined) { + throw Error(Errors[Errors.UNABLE_TO_SIGN_AGGREGATE_TRANSACTION]); } - private _signAggregate(aggregateTransaction: AggregateTransaction, signers: Account[]): SignedTransaction { - // fetch the first signer - const mainSigner = signers[0]; - - // fetch the signer from index 1 till n - const cosignatories = drop(signers); - - // init signitTransaction - let signedTransaction: SignedTransaction; - - if (cosignatories.length === 0) { - // it should be a 1-n account - signedTransaction = mainSigner.sign(aggregateTransaction); - } else { - // if we have cosignatories that needs to sign - signedTransaction = mainSigner.signTransactionWithCosignatories( - aggregateTransaction, - cosignatories, - ); - } - - return signedTransaction; + // init signitTransaction + let signedTransaction: SignedTransaction; + + if (signers.length === 0) { + // it should be a 1-n account + signedTransaction = mainSigner.sign(aggregateTransaction); + } else { + // if we have cosignatories that needs to sign + signedTransaction = mainSigner.signTransactionWithCosignatories( + aggregateTransaction, + signers, + ); } + + return signedTransaction; + } } diff --git a/src/model/apostille/PublicApostille.ts b/src/model/apostille/PublicApostille.ts index 701e976..368032b 100644 --- a/src/model/apostille/PublicApostille.ts +++ b/src/model/apostille/PublicApostille.ts @@ -8,7 +8,7 @@ import { HashFunction } from '../../hash/HashFunction'; class PublicApostille { /** - * @description - the hash uncluding the magical byte of this public apostille + * @description - the hash including the magical byte of this public apostille * @private * @memberof PublicApostille */ @@ -17,8 +17,7 @@ class PublicApostille { /** * Creates an instance of PublicApostille. * @param {string} fileName - the digital file name - * @param {NetworkType} networkType - network type - * @param {string} [sinkAddress] - the sink address to use + * @param {Address} sinkAddress - the sink address to use * @memberof PublicApostille */ constructor( diff --git a/src/model/repository/HistoricalEndpoints.ts b/src/model/repository/HistoricalEndpoints.ts index 4dce31d..89d6945 100644 --- a/src/model/repository/HistoricalEndpoints.ts +++ b/src/model/repository/HistoricalEndpoints.ts @@ -11,4 +11,4 @@ export enum HistoricalEndpoints { // mijin_test 'http://api.beta.catapult.mijin.io:3000' = 0x90, } - // should be used as HistoricalEndpoints[network] // get the address + // should be used as HistoricalEndpoints[networkType] // get the address diff --git a/src/model/repository/Sinks.ts b/src/model/repository/Sinks.ts index 2cdecd8..d062b4b 100644 --- a/src/model/repository/Sinks.ts +++ b/src/model/repository/Sinks.ts @@ -14,4 +14,4 @@ export enum Sinks { MIJIN_TEST = 0x90, } -// should be used as Sinks[network] // get the address +// should be used as Sinks[networkType] // get the address diff --git a/src/types/Errors.ts b/src/types/Errors.ts index 28db00f..1dfb39a 100644 --- a/src/types/Errors.ts +++ b/src/types/Errors.ts @@ -34,4 +34,6 @@ export enum Errors { CREATION_TRANSACTIONS_NOT_FOUND, + UNABLE_TO_SIGN_AGGREGATE_TRANSACTION, + } From 1292df19225bc06472a2104fd97d699bc5faf2ef Mon Sep 17 00:00:00 2001 From: aizaiz Date: Tue, 27 Nov 2018 15:27:49 +0800 Subject: [PATCH 3/5] fix(ApostilleHttp): Fix error catcher for some methods --- src/infrastructure/ApostilleHttp.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/infrastructure/ApostilleHttp.ts b/src/infrastructure/ApostilleHttp.ts index 1c7e6df..3c287f4 100644 --- a/src/infrastructure/ApostilleHttp.ts +++ b/src/infrastructure/ApostilleHttp.ts @@ -159,6 +159,8 @@ export class ApostilleHttp { } else { reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); } + }).catch((err) => { + reject(err); }); }); } @@ -202,7 +204,7 @@ export class ApostilleHttp { resolve(unconfirmedTransactions); }, (err) => { // network or comunication problem - resolve(err); + reject(err); }); }); @@ -220,7 +222,7 @@ export class ApostilleHttp { resolve(transactions); }, (err) => { // network or comunication problem - resolve(err); + reject(err); }); }); From 40b73dbaba37d4034c7077a87c62dad51f0abb4b Mon Sep 17 00:00:00 2001 From: Jonathan Tey Date: Tue, 27 Nov 2018 16:10:27 +0800 Subject: [PATCH 4/5] test: Update tests to conform to version 7.0.0 refactor --- src/infrastructure/ApostilleHttp.ts | 98 ++++--- tests/e2e/PrivateApostille/Apostille.spec.ts | 253 ++++-------------- tests/e2e/PrivateApostille/Getters.spec.ts | 58 ---- tests/e2e/PrivateApostille/HDAccount.spec.ts | 49 ---- tests/e2e/PrivateApostille/Setters.spec.ts | 29 -- tests/e2e/PrivateApostille/nem-sdk.spec.ts | 44 +++ tests/unit/model/apostille/Apostille.spec.ts | 57 ++-- .../apostille/ApostillePublicAccount.spec.ts | 39 ++- 8 files changed, 213 insertions(+), 414 deletions(-) delete mode 100644 tests/e2e/PrivateApostille/Getters.spec.ts delete mode 100644 tests/e2e/PrivateApostille/HDAccount.spec.ts delete mode 100644 tests/e2e/PrivateApostille/Setters.spec.ts create mode 100644 tests/e2e/PrivateApostille/nem-sdk.spec.ts diff --git a/src/infrastructure/ApostilleHttp.ts b/src/infrastructure/ApostilleHttp.ts index 16c7714..1fabcf4 100644 --- a/src/infrastructure/ApostilleHttp.ts +++ b/src/infrastructure/ApostilleHttp.ts @@ -1,5 +1,5 @@ import { sortBy } from 'lodash'; -import { AccountHttp, Address, AggregateTransaction, Listener, PublicAccount, QueryParams, SignedTransaction, Transaction, TransactionHttp, TransactionInfo, TransferTransaction } from 'nem2-sdk'; +import { AccountHttp, Address, AggregateTransaction, Listener, PublicAccount, QueryParams, SignedTransaction, Transaction, TransactionAnnounceResponse, TransactionHttp, TransactionInfo, TransferTransaction } from 'nem2-sdk'; import { filter, mergeMap } from 'rxjs/operators'; import { Errors } from '../types/Errors'; @@ -13,40 +13,66 @@ export class ApostilleHttp { this.accountHttp = new AccountHttp(url); } - public announce(signedTransaction: SignedTransaction): Promise { - return new Promise((resolve, reject) => { + /** + * Generic announce method + * + * @param {SignedTransaction} signedTransaction + * @returns {Promise} + * @memberof ApostilleHttp + */ + public announce(signedTransaction: SignedTransaction): Promise { + return new Promise((resolve, reject) => { this.transactionHttp.announce(signedTransaction) .subscribe((x) => resolve(x), (err) => reject(err)); }); } + /** + * Helper method to announce aggregate bonded transaction with lock funds + * + * @param {PublicAccount} cosignatoryAccount + * @param {SignedTransaction} signedAggregateBondedTransaction + * @param {SignedTransaction} signedLockFundsTransaction + * @param {Listener} listener + * @returns {Promise} + * @memberof ApostilleHttp + */ public announceAggregateBonded( cosignatoryAccount: PublicAccount, signedAggregateBondedTransaction: SignedTransaction, signedLockFundsTransaction: SignedTransaction, - listener: Listener): void { - - listener.open().then(() => { - - this.transactionHttp - .announce(signedLockFundsTransaction) - .subscribe((x) => console.log(x), (err) => console.error(err)); - - listener - .confirmed(cosignatoryAccount.address) - .pipe( - filter((transaction) => transaction.transactionInfo !== undefined - && transaction.transactionInfo.hash === signedLockFundsTransaction.hash), - mergeMap((ignored) => this.transactionHttp.announceAggregateBonded( - signedAggregateBondedTransaction)), - ) - .subscribe((announcedAggregateBonded) => console.log(announcedAggregateBonded), - (err) => console.error(err)); + listener: Listener): Promise { + + return new Promise((resolve, reject) => { + listener.open().then(() => { + + // Announce lock funds first + this.transactionHttp + .announce(signedLockFundsTransaction) + .subscribe((x) => console.log(x), (err) => reject(err)); + + // Watch for lock funds confirmation before announcing aggregate bonded + listener + .confirmed(cosignatoryAccount.address) + .pipe( + filter((transaction) => transaction.transactionInfo !== undefined + && transaction.transactionInfo.hash === signedLockFundsTransaction.hash), + mergeMap((ignored) => this.transactionHttp.announceAggregateBonded( + signedAggregateBondedTransaction)), + ) + .subscribe((announcedAggregateBonded) => { + resolve(announcedAggregateBonded); + }, (err) => { + reject(err); + }); + }); }); + } /** - * @description - cheks on chain if there are any transactions announced + * @description - checks on chain if account exists + * @param {PublicAccount} publicAccount * @returns {Promise} * @memberof ApostilleAccount */ @@ -59,10 +85,10 @@ export class ApostilleHttp { } else { // then check transactions const transactions = await this._transactions(publicAccount); - if (transactions.length) { + if (transactions.length > 0) { return true; } else { - return true; + return false; } } } catch (err) { @@ -71,7 +97,7 @@ export class ApostilleHttp { } /** - * @description - get cosignatories of the account + * @description - get cosignatories of an account * @returns {Promise} * @memberof ApostilleHttp */ @@ -87,15 +113,14 @@ export class ApostilleHttp { } /** - * @description - get first transaction - * @static + * @description - Check if account is owned * @returns {Promise} * @memberof ApostilleHttp */ public async isOwned(address: Address): Promise { try { - const cossignatories = await this.getCosignatories(address); - if (cossignatories.length > 0) { + const cosignatories = await this.getCosignatories(address); + if (cosignatories.length > 0) { return true; } else { return false; @@ -149,16 +174,11 @@ export class ApostilleHttp { innerTransactions, ['transactionInfo.index']); const firstInnerTransaction = sortedInnerTransactions[0]; if (firstInnerTransaction instanceof TransferTransaction) { - resolve (firstInnerTransaction); - } else { - reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); + resolve(firstInnerTransaction); } - } else { - reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); } - } else { - reject (Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); } + reject(Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]); }); }); } @@ -169,7 +189,7 @@ export class ApostilleHttp { * @returns {Promise} * @memberof CertificateHistory */ - public _fetchAllTransactions(publicAccount: PublicAccount): Promise { + public _fetchAllTransactions(publicAccount: PublicAccount): Promise { return new Promise(async (resolve, reject) => { let nextId: string = ''; const pageSize: number = 100; @@ -192,7 +212,7 @@ export class ApostilleHttp { private _unconfirmedTransactions( publicAccount: PublicAccount, - queryParams?: QueryParams | undefined): Promise { + queryParams ?: QueryParams | undefined): Promise { return new Promise((resolve, reject) => { this.accountHttp.unconfirmedTransactions( @@ -210,7 +230,7 @@ export class ApostilleHttp { private _transactions( publicAccount: PublicAccount, - queryParams?: QueryParams | undefined): Promise { + queryParams ?: QueryParams | undefined): Promise { return new Promise((resolve, reject) => { this.accountHttp.transactions( diff --git a/tests/e2e/PrivateApostille/Apostille.spec.ts b/tests/e2e/PrivateApostille/Apostille.spec.ts index 7375db9..fea71f6 100644 --- a/tests/e2e/PrivateApostille/Apostille.spec.ts +++ b/tests/e2e/PrivateApostille/Apostille.spec.ts @@ -1,214 +1,59 @@ -// import { Account, NetworkType } from 'nem2-sdk'; +import { Account, NetworkType } from 'nem2-sdk'; +import { Apostille, ApostilleHttp, HistoricalEndpoints } from '../../../index'; + +// A funny but valid private key +const sk = 'aaaaaaaaaaeeeeeeeeeebbbbbbbbbb5555555555dddddddddd1111111111aaee'; +const generator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); +const apostilleHttp = new ApostilleHttp(HistoricalEndpoints[NetworkType.MIJIN_TEST]); +const seed = 'KV_,x797taRe}Y<+'; +const PrivateApostille1 = Apostille.init(seed, generator); +const hdAccountInformation = { + address: 'SDTE6Z-XQAQ46-FDJ5P7-MSU43E-BNT4SR-7C7EKU-HHL5', + privateKey: 'B9EF817A39DAEB43179EE9129E5D592410B8A47FA4870A4EC16024575E51A608'.toUpperCase(), + publicKey: '9C0C770BD1E1506FD207A8D783E0E4AC00D98B6D790401573519D82133474B90'.toUpperCase(), +}; + +beforeAll(() => { + jest.setTimeout(10000); +}); -// const seed = '.N:@N%5SVjj3Wkmr-'; -// // A funny but valid private key -// const sk = 'aaaaaaaaaaeeeeeeeeeebbbbbbbbbb5555555555dddddddddd1111111111aaee'; -// const generator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); +it('should correctly generate a private apostille via a private key', () => { + expect(PrivateApostille1.HDAccount.privateKey).toMatch(hdAccountInformation.privateKey); + expect(PrivateApostille1.HDAccount.publicKey).toMatch(hdAccountInformation.publicKey); + expect(PrivateApostille1.HDAccount.address.pretty()).toMatch(hdAccountInformation.address); +}); -// beforeAll(() => { -// jest.setTimeout(10000); -// }); +describe('isCreated function should work properly', () => { -describe('Create functionn should work properly', () => { - it.skip('skip', () => { - expect('').toMatch(''); + it('should return false before creation', async () => { + const privateApostille = Apostille.init('QUleqZedaOUtlSh', generator); + expect.assertions(1); + return apostilleHttp.isCreated(privateApostille.HDAccount.publicAccount).then((result) => { + expect(result).toBeFalsy(); + }); }); - // it.skip('should throw an error if you try to create an apostille more than once', async () => { - // const privateApostille = Apostille.init(seed, generator); - // const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); - // const initiator = new Initiator(creator); - // expect.assertions(1); - // await privateApostille.create(initiator, 'raw'); - // return privateApostille.create(initiator, 'raw').catch((e) => { - // expect(e.message).toMatch(Errors[Errors.APOSTILLE_ALREADY_CREATED]); - // }); - // }); - - // it.skip('should create a transfer transaction', () => { - // const privateApostille = Apostille.init(seed, generator); - // const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); - // const initiator = new Initiator(creator); - // return privateApostille.create(initiator, 'raw').then(() => { - // // tslint:disable-next-line:no-string-literal - // expect(privateApostille['transactions'][0].type).toEqual(TransactionType.TRANSFER); - // }); - // }); - - // it.skip('should create an aggregate complete transaction', () => { - // const privateApostille = Apostille.init(seed, generator); - // const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); - // const initiator = new Initiator(creator, creator.publicAccount, true); - // return privateApostille.create(initiator, 'raw').then(() => { - // // tslint:disable-next-line:no-string-literal - // expect(privateApostille['transactions'][0].type).toEqual(TransactionType.AGGREGATE_COMPLETE); - // }); - // }); - - // it.skip('should create an aggregate bounded transaction', () => { - // const privateApostille = Apostille.init(seed, generator); - // const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); - // const initiator = new Initiator(creator, creator.publicAccount, false); - // return privateApostille.create(initiator, 'raw').then(() => { - // // tslint:disable-next-line:no-string-literal - // expect(privateApostille['transactions'][0].type).toEqual(TransactionType.AGGREGATE_BONDED); - // }); - // }); + it('should return true after creation', async () => { + const privateApostille = Apostille.init('new random seed', generator); + const apostillePA = privateApostille.apostillePublicAccount; + const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); + expect.assertions(1); + const creationTransaction = apostillePA.update('raw'); + const signedTransaction = apostillePA.sign(creationTransaction, creator); + await apostilleHttp.announce(signedTransaction); + return apostilleHttp.isCreated(apostillePA.publicAccount).then((result) => { + expect(result).toBeTruthy(); + }); + }); + it('should return false before an announce', () => { + const MTgenerator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); + const apostilleMT = Apostille.init('QUleqZedaOUtlSh', MTgenerator); + return apostilleHttp.isCreated(apostilleMT.HDAccount.publicAccount).then((result) => { + expect(result).toBeFalsy(); + }); + }); }); -// describe('update function should work properly', () => { - -// it.skip('should throw an error if we try to update before creating', async () => { -// const privateApostille = Apostille.init(seed, generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const initiator = new Initiator(creator); -// expect.assertions(1); -// return privateApostille.update(initiator, 'raw').catch((e) => { -// expect(e.message).toMatch(Errors[Errors.APOSTILLE_NOT_CREATED]); -// }); -// }); - -// it.skip('should create a transfer transaction', async () => { -// const privateApostille = Apostille.init(seed, generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const initiator = new Initiator(creator); -// expect.assertions(1); -// await privateApostille.create(initiator, 'raw'); -// await privateApostille.update(initiator, 'update'); -// // tslint:disable-next-line:no-string-literal -// expect(privateApostille['transactions'][1].type).toEqual(TransactionType.TRANSFER); -// }); - -// it.skip('should create an aggregate complete transaction', async () => { -// const privateApostille = Apostille.init(seed, generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const initiator = new Initiator(creator, creator.publicAccount, true); -// expect.assertions(1); -// await privateApostille.create(initiator, 'raw'); -// await privateApostille.update(initiator, 'update'); -// // tslint:disable-next-line:no-string-literal -// expect(privateApostille['transactions'][0].type).toEqual(TransactionType.AGGREGATE_COMPLETE); -// }); - -// it.skip('should create an aggregate bounded transaction', async () => { -// const privateApostille = Apostille.init(seed, generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const initiator = new Initiator(creator, creator.publicAccount, false); -// expect.assertions(1); -// await privateApostille.create(initiator, 'raw'); -// await privateApostille.update(initiator, 'update'); -// // tslint:disable-next-line:no-string-literal -// expect(privateApostille['transactions'][0].type).toEqual(TransactionType.AGGREGATE_BONDED); -// }); - -// }); - -// describe('associate function should work properly', () => { - -// it.skip('should create an aggregate bounded transaction', async () => { -// const privateApostille = Apostille.init(seed, generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const initiator = new Initiator(creator, creator.publicAccount, false); -// expect.assertions(1); -// await privateApostille.create(initiator, 'raw'); -// await privateApostille.update(initiator, 'update'); -// privateApostille.associate([initiator.account.publicAccount], 1, 1); -// // tslint:disable-next-line:no-string-literal -// expect(privateApostille['transactions'][2].type).toEqual(TransactionType.MODIFY_MULTISIG_ACCOUNT); -// }); - -// }); - -// describe('transfer function should work properly', () => { - -// it.skip('should create an aggregate complete transaction', async () => { -// const privateApostille = Apostille.init(seed, generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// // const initiator = new Initiator(creator, creator.publicAccount, false); -// expect.assertions(1); -// privateApostille.transfer([creator], true, [creator.publicAccount], [creator.publicAccount], 0, 0); -// // tslint:disable-next-line:no-string-literal -// expect(privateApostille['transactions'][0].type).toEqual(TransactionType.AGGREGATE_COMPLETE); -// }); - -// it.skip('should create an aggregate complete transaction', async () => { -// const privateApostille = Apostille.init(seed, generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// // const initiator = new Initiator(creator, creator.publicAccount, false); -// expect.assertions(1); -// privateApostille.transfer([creator], false, [], [], 0, 0); -// // tslint:disable-next-line:no-string-literal -// expect(privateApostille['transactions'][0].type).toEqual(TransactionType.AGGREGATE_BONDED); -// }); - -// }); - -// describe('isCreated function should work properly', () => { - -// it.skip('should return false before creation', async () => { -// const privateApostille = Apostille.init('QUleqZedaOUtlSh', generator); -// expect.assertions(1); -// return privateApostille.isCreated().then((result) => { -// expect(result).toBeFalsy(); -// }); -// }); - -// it('should return true after creation', async () => { -// const privateApostille = Apostille.init('new random seed', generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const initiator = new Initiator(creator); -// expect.assertions(1); -// await privateApostille.create(initiator, 'raw'); -// return privateApostille.isCreated().then((result) => { -// expect(result).toBeTruthy(); -// }); -// }); - -// it.skip('should return true for an already created apostille', async () => { -// const privateApostille = Apostille.init('MIJIN_TEST', generator); -// expect.assertions(1); -// return privateApostille.isCreated().then((result) => { -// expect(result).toBeTruthy(); -// }); -// }); - -// it.skip('should throw an error if we don\'t specefy mijin endpoint url', () => { -// const MJgenerator = Account.createFromPrivateKey(sk, NetworkType.MIJIN); -// try { -// return Apostille.init('k7u*VTsVCk6h,FdN', MJgenerator); -// } catch (e) { -// expect(e.message).toMatch(Errors[Errors.MIJIN_ENDPOINT_NEEDED]); -// } -// }); - -// it.skip('should return false before an announce', () => { -// const MTgenerator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const apostilleMT = Apostille.init('QUleqZedaOUtlSh', MTgenerator); -// return apostilleMT.isCreated().then((MT) => { -// expect(MT).toBeFalsy(); -// }); -// }); - -// it.skip('should return true after an announce', async () => { -// const privateApostille = Apostille.init('_934@Ve*,tM(3MN-', generator); -// const creator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const initiator = new Initiator(creator); -// privateApostille.created = true; -// await privateApostille.update(initiator, 'update'); -// await privateApostille.announce(); -// return privateApostille.isCreated().then((result) => { -// expect(result).toBeTruthy(); -// }); -// }); - -// it.skip('should return true for an already announced apostille', () => { -// const privateApostille = Apostille.init('MIJIN_TEST', generator); -// return privateApostille.isCreated().then((result) => { -// expect(result).toBeTruthy(); -// }); -// }); -// }); - // TODO: check the order of transactions // TODO: no transfer transaction should exist after a multisig modification diff --git a/tests/e2e/PrivateApostille/Getters.spec.ts b/tests/e2e/PrivateApostille/Getters.spec.ts deleted file mode 100644 index d023a4b..0000000 --- a/tests/e2e/PrivateApostille/Getters.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -// import { Account, NetworkType } from 'nem2-sdk'; -// import { Apostille } from '../../../index'; - -// const seed = 'KV_,x797taRe}Y<+'; -// // A funny but valid private key -// const sk = 'aaaaaaaaaaeeeeeeeeeebbbbbbbbbb5555555555dddddddddd1111111111aaee'; - -// const generator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// const signer = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// // creation payload -// const payload = 'Apostille is awesome !'; - -// const hdAccountInformation = { -// address: 'SDTE6Z-XQAQ46-FDJ5P7-MSU43E-BNT4SR-7C7EKU-HHL5', -// privateKey: 'B9EF817A39DAEB43179EE9129E5D592410B8A47FA4870A4EC16024575E51A608'.toUpperCase(), -// publicKey: '9C0C770BD1E1506FD207A8D783E0E4AC00D98B6D790401573519D82133474B90'.toUpperCase(), -// }; - -// const PrivateApostille1 = Apostille.init(seed, generator); -// const PrivateApostille2 = Apostille.init(seed, generator); - -describe('Getters should work properly', () => { - it.skip('skip', () => { - expect('').toMatch(''); - }); - - // it('should correctly generate a private apostille via a private key', () => { - // expect(PrivateApostille1.privateKey).toMatch(hdAccountInformation.privateKey); - // expect(PrivateApostille1.publicKey).toMatch(hdAccountInformation.publicKey); - // expect(PrivateApostille1.address.pretty()).toMatch(hdAccountInformation.address); - // }); - - // it('should return the generator public account', () => { - // expect(PrivateApostille1.generator) - // .toMatchObject(signer.publicAccount); - // }); - - // it('creator should be undefined', () => { - // expect(PrivateApostille1.creator).toBeUndefined(); - // }); - - // it('creator should be a valid account', async () => { - // const creator = new Initiator(signer); - // await PrivateApostille1.create(creator, payload); - // expect(PrivateApostille1.creator).toMatchObject(creator.account); - // }); - - // it('multisig creator should be a valid public account', async () => { - // const dumpMultisigCreator = new Initiator(signer, signer.publicAccount, true); - // await PrivateApostille2.create(dumpMultisigCreator, payload); - // if (dumpMultisigCreator.multisigAccount && PrivateApostille2.creator) { - // expect(PrivateApostille2.creator).toMatchObject(dumpMultisigCreator.multisigAccount); - // expect(PrivateApostille2.creator.publicKey).toMatch(dumpMultisigCreator.multisigAccount.publicKey); - // } - // }); -}); - -// TODO: a getter function for getting all the owners of the apostille diff --git a/tests/e2e/PrivateApostille/HDAccount.spec.ts b/tests/e2e/PrivateApostille/HDAccount.spec.ts deleted file mode 100644 index 2586ac3..0000000 --- a/tests/e2e/PrivateApostille/HDAccount.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -// import * as nemDefault from 'nem-sdk'; -// import { Account, NetworkType } from 'nem2-sdk'; -// import { Apostille } from '../../../index'; - -// const nem = nemDefault.default; - -// const seed = 'NEM is Awesome!'; -// // A funny but valid private key -// const sk = 'aaaaaaaaaaeeeeeeeeeebbbbbbbbbb5555555555dddddddddd1111111111aaee'; -// const generator = Account.createFromPrivateKey(sk, NetworkType.TEST_NET); -// // Create a common object holding key -// const common = nem.model.objects.create('common')('', sk); - -// // Simulate the file content -// const payload = nem.crypto.js.enc.Utf8.parse('Apostille is awesome !'); - -// // Create the Apostille -// const oldPrivateApostille = nem.model.apostille.create( -// common, -// 'NEM is Awesome!', -// payload, -// 'Test Apostille', -// // tslint:disable-next-line:no-string-literal -// nem.model.apostille.hashing['SHA256'], -// false, {}, true, -// nem.model.network.data.testnet.id); - -// const newPrivateApostille = Apostille.init(seed, generator); - -describe('HD account generation should be correct', () => { - it.skip('skip', () => { - expect('').toMatch(''); - }); - - // it.skip('private key should be valid', () => { - // console.log('PRIVATE_KEY', newPrivateApostille.privateKey); - // expect(nem.utils.helpers.isPrivateKeyValid(newPrivateApostille.privateKey)).toBeTruthy(); - // }); - - // it.skip('public key should be valid', () => { - // expect(nem.utils.helpers.isPublicKeyValid(newPrivateApostille.publicKey)).toBeTruthy(); - // }); - - // it.skip('should generate the same HD account as old apostille', () => { - // expect( - // oldPrivateApostille.data.dedicatedAccount.privateKey.toUpperCase() === newPrivateApostille.privateKey, - // ).toBeTruthy(); - // }); -}); diff --git a/tests/e2e/PrivateApostille/Setters.spec.ts b/tests/e2e/PrivateApostille/Setters.spec.ts deleted file mode 100644 index 6c62daf..0000000 --- a/tests/e2e/PrivateApostille/Setters.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -// import { Account, NetworkType } from 'nem2-sdk'; -// import { Apostille } from '../../../index'; - -// const seed = 'KV_,x797taRe}t<+'; -// // A funny but valid private key -// const sk = 'aaaaaaaaaaeeeeeeeeeebbbbbbbbbb5555555555dddddddddd1111111111aaee'; - -// const generator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// // const signer = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); -// // creation payload -// // const payload = 'Apostille is awesome !'; - -// const PrivateApostille = Apostille.init(seed, generator); - -describe('Setters should work properly', () => { - - it.skip('skip', () => { - expect('').toMatch(''); - }); - - // it.skip('create setter should work properly', () => { - // // tslint:disable-next-line:no-string-literal - // expect(PrivateApostille['_created']).toBeFalsy(); - // PrivateApostille.created = true; - // // tslint:disable-next-line:no-string-literal - // expect(PrivateApostille['_created']).toBeTruthy(); - // }); - -}); diff --git a/tests/e2e/PrivateApostille/nem-sdk.spec.ts b/tests/e2e/PrivateApostille/nem-sdk.spec.ts new file mode 100644 index 0000000..975cbe4 --- /dev/null +++ b/tests/e2e/PrivateApostille/nem-sdk.spec.ts @@ -0,0 +1,44 @@ +import * as nemDefault from 'nem-sdk'; +import { Account, NetworkType } from 'nem2-sdk'; +import { Apostille } from '../../../index'; + +const nem = nemDefault.default; + +const seed = 'NEM is Awesome!'; +// A funny but valid private key +const sk = 'aaaaaaaaaaeeeeeeeeeebbbbbbbbbb5555555555dddddddddd1111111111aaee'; +const generator = Account.createFromPrivateKey(sk, NetworkType.TEST_NET); +// Create a common object holding key +const common = nem.model.objects.create('common')('', sk); + +// Simulate the file content +const payload = nem.crypto.js.enc.Utf8.parse('Apostille is awesome !'); + +// Create the Apostille +const oldPrivateApostille = nem.model.apostille.create( + common, + 'NEM is Awesome!', + payload, + 'Test Apostille', + // tslint:disable-next-line:no-string-literal + nem.model.apostille.hashing['SHA256'], + false, {}, true, + nem.model.network.data.testnet.id); + +const newPrivateApostille = Apostille.init(seed, generator); + +describe('HD account generation should be correct', () => { + it('private key should be valid', () => { + expect(nem.utils.helpers.isPrivateKeyValid(newPrivateApostille.HDAccount.privateKey)).toBeTruthy(); + }); + + it('public key should be valid', () => { + expect(nem.utils.helpers.isPublicKeyValid(newPrivateApostille.HDAccount.publicKey)).toBeTruthy(); + }); + + it('should generate the same HD account as old apostille', () => { + expect( + oldPrivateApostille.data.dedicatedAccount.privateKey.toUpperCase() === newPrivateApostille.HDAccount.privateKey, + ).toBeTruthy(); + }); +}); diff --git a/tests/unit/model/apostille/Apostille.spec.ts b/tests/unit/model/apostille/Apostille.spec.ts index c683ee5..59df839 100644 --- a/tests/unit/model/apostille/Apostille.spec.ts +++ b/tests/unit/model/apostille/Apostille.spec.ts @@ -1,4 +1,4 @@ -import { Account, NetworkType, PublicAccount, SignedTransaction } from 'nem2-sdk'; +import { Account, NetworkType, PublicAccount, TransactionType } from 'nem2-sdk'; import { Apostille } from '../../../../src/model/apostille/Apostille'; const seed = '.N:@N%5SVjj3Wkmr-'; @@ -8,40 +8,43 @@ const sk = 'aaaaaaaaaaeeeeeeeeeebbbbbbbbbb5555555555dddddddddd1111111111aaee'; describe('Apostille class should work properly with MIJIN_TEST Network Type', () => { - const generator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); - const apostille = Apostille.init(seed, generator); + const generator = Account.createFromPrivateKey(sk, NetworkType.MIJIN_TEST); + const apostille = Apostille.init(seed, generator); - it('Apostille.init with MIJIN_TEST NetworkType should return correct HDAccount', () => { - expect(apostille.HDAccount.privateKey).toMatch( - 'E26A117C038068239E312E04F2B43DCC839D31BE7471D04DCCE905C2DC164107'); - }); + it('Apostille.init with MIJIN_TEST NetworkType should return correct HDAccount', () => { + expect(apostille.HDAccount.privateKey).toMatch( + 'E26A117C038068239E312E04F2B43DCC839D31BE7471D04DCCE905C2DC164107'); + }); + + it('should return correct PublicApostilleAccount', () => { + expect(apostille.apostillePublicAccount.publicAccount.equals(apostille.HDAccount.publicAccount)).toBeTruthy(); + }); + + describe('associate function should work properly', () => { - it('should return correct PublicApostilleAccount', () => { - expect(apostille.apostillePublicAccount.publicAccount.equals(apostille.HDAccount.publicAccount)).toBeTruthy(); + it('should create a ModifyMultisigAccount transaction', async () => { + const signedTransaction = apostille.associate([generator.publicAccount], 1, 1); + expect(signedTransaction.type).toEqual(TransactionType.MODIFY_MULTISIG_ACCOUNT); }); it('should returned correct signer', () => { - const ownerPublicAccount = PublicAccount.createFromPublicKey( - 'E41D411DE4FEF6FA3097D869FAB918DB8ADF20779F464C27EDE3BA0762F4D85D', - NetworkType.MIJIN_TEST, - ); - - const signedTransaction: SignedTransaction = apostille.associate( - [ownerPublicAccount], - 1, - 1, - ); - - expect(signedTransaction.signer).toMatch(apostille.HDAccount.publicAccount.publicKey); + const ownerPublicAccount = PublicAccount.createFromPublicKey( + 'E41D411DE4FEF6FA3097D869FAB918DB8ADF20779F464C27EDE3BA0762F4D85D', + NetworkType.MIJIN_TEST, + ); + const signedTransaction = apostille.associate([ownerPublicAccount], 1, 1); + expect(signedTransaction.signer).toMatch(apostille.HDAccount.publicAccount.publicKey); }); + + }); }); describe('Apostille class should work properly with MAIN_NET Network Type', () => { - const generator = Account.createFromPrivateKey(sk, NetworkType.MAIN_NET); - const apostille = Apostille.init(seed, generator); + const generator = Account.createFromPrivateKey(sk, NetworkType.MAIN_NET); + const apostille = Apostille.init(seed, generator); - it('Apostille.init with MAIN_NET NetworkType should return correct HDAccount', () => { - expect(apostille.HDAccount.privateKey).toMatch( - '61AC074E12209092FAECC6625FB28D42606E83B1FDB90591DBF0F5C762009300'); - }); + it('Apostille.init with MAIN_NET NetworkType should return correct HDAccount', () => { + expect(apostille.HDAccount.privateKey).toMatch( + '61AC074E12209092FAECC6625FB28D42606E83B1FDB90591DBF0F5C762009300'); + }); }); diff --git a/tests/unit/model/apostille/ApostillePublicAccount.spec.ts b/tests/unit/model/apostille/ApostillePublicAccount.spec.ts index 7bcc035..61352de 100644 --- a/tests/unit/model/apostille/ApostillePublicAccount.spec.ts +++ b/tests/unit/model/apostille/ApostillePublicAccount.spec.ts @@ -1,6 +1,7 @@ -import { Account, ModifyMultisigAccountTransaction, NetworkType, PublicAccount, SignedTransaction, TransferTransaction } from 'nem2-sdk'; +import { Account, NetworkType, PublicAccount, TransactionType } from 'nem2-sdk'; import { SHA256 } from '../../../../src/hash/sha256'; import { ApostillePublicAccount } from '../../../../src/model/apostille/ApostillePublicAccount'; +import { Errors } from '../../../../src/types/Errors'; const getPublicApostilleAccount = ((publicKey: string, networkType: NetworkType): ApostillePublicAccount => { // Account 1 @@ -47,25 +48,32 @@ describe('apostille public account transaction methods should work properly', () NetworkType.MIJIN_TEST); it('should return correct update transaction', () => { - const updateTransaction: TransferTransaction = apostillePublicAccount.update( + const updateTransaction = apostillePublicAccount.update( 'LuxTag is awesome', []); expect(updateTransaction.recipient).toEqual(apostillePublicAccount.publicAccount.address); }); + it('Create function should be a transfer type transaction', () => { + const updateTransaction = apostillePublicAccount.update( + 'LuxTag is awesome', + []); + expect(updateTransaction.type).toEqual(TransactionType.TRANSFER); + }); + it('should return correct signed update transaction', () => { - const updateTransaction: TransferTransaction = apostillePublicAccount.update( + const updateTransaction = apostillePublicAccount.update( 'LuxTag is awesome', []); - const signedTransaction: SignedTransaction = apostillePublicAccount.sign(updateTransaction, signer); + const signedTransaction = apostillePublicAccount.sign(updateTransaction, signer); expect(signedTransaction.signer).toMatch(signer.publicAccount.publicKey); }); it('should return correct signed update transaction if hash provided', () => { - const updateTransaction: TransferTransaction = apostillePublicAccount.update( + const updateTransaction = apostillePublicAccount.update( 'LuxTag is awesome', []); - const signedTransaction: SignedTransaction = apostillePublicAccount.sign( + const signedTransaction = apostillePublicAccount.sign( updateTransaction, signer, new SHA256()); @@ -73,7 +81,7 @@ describe('apostille public account transaction methods should work properly', () }); it('should return correct transfer transaction', () => { - const transferTransaction: ModifyMultisigAccountTransaction = apostillePublicAccount.transfer( + const transferTransaction = apostillePublicAccount.transfer( [newOwner], [signer.publicAccount], 0, @@ -81,8 +89,22 @@ describe('apostille public account transaction methods should work properly', () expect(transferTransaction.modifications.length).toEqual(2); }); + it('should throw error if no cosignatories are present', () => { + const transferTransaction = apostillePublicAccount.transfer( + [newOwner], + [signer.publicAccount], + 0, + 0); + expect(() => { + apostillePublicAccount.signAggregate( + transferTransaction, + [], + true); + }).toThrowError(Errors[Errors.UNABLE_TO_SIGN_AGGREGATE_TRANSACTION]); + }); + it('should return signed aggregate complete transfer transaction', () => { - const transferTransaction: ModifyMultisigAccountTransaction = apostillePublicAccount.transfer( + const transferTransaction = apostillePublicAccount.transfer( [newOwner], [signer.publicAccount], 0, @@ -165,4 +187,5 @@ describe('apostille public account transaction methods should work properly', () signer); expect(signedLockFundsTransaction.signer).toMatch(signer.publicKey); }); + }); From 4f00f2061c96dec916712c1dea57225230a6db59 Mon Sep 17 00:00:00 2001 From: Jonathan Tey Date: Tue, 27 Nov 2018 16:24:48 +0800 Subject: [PATCH 5/5] test(ApostillePublicAccount): Add test for mismatched networkType --- .../model/apostille/ApostillePublicAccount.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/unit/model/apostille/ApostillePublicAccount.spec.ts b/tests/unit/model/apostille/ApostillePublicAccount.spec.ts index 61352de..c0fd48a 100644 --- a/tests/unit/model/apostille/ApostillePublicAccount.spec.ts +++ b/tests/unit/model/apostille/ApostillePublicAccount.spec.ts @@ -61,6 +61,18 @@ describe('apostille public account transaction methods should work properly', () expect(updateTransaction.type).toEqual(TransactionType.TRANSFER); }); + it('should not sign if apostille and signer are from different networkTypes', () => { + const alienAccount = Account.createFromPrivateKey( + 'aaaaaaaaaaeeeeeeeeeebbbbbbbbbb5555555555dddddddddd1111111111aaee', + NetworkType.MAIN_NET); + const updateTransaction = apostillePublicAccount.update( + 'LuxTag is awesome', + []); + expect(() => { + apostillePublicAccount.sign(updateTransaction, alienAccount); + }).toThrowError(Errors[Errors.NETWORK_TYPE_MISMATCHED]); + }); + it('should return correct signed update transaction', () => { const updateTransaction = apostillePublicAccount.update( 'LuxTag is awesome',