diff --git a/e2e/infrastructure/AccountHttp.spec.ts b/e2e/infrastructure/AccountHttp.spec.ts index 9f38b7dc40..ee00debece 100644 --- a/e2e/infrastructure/AccountHttp.spec.ts +++ b/e2e/infrastructure/AccountHttp.spec.ts @@ -62,6 +62,23 @@ describe('AccountHttp', () => { }); }); + describe('getAccountProperty', () => { + it('should call getAccountProperty successfully', (done) => { + accountHttp.getAccountProperty(publicAccount).subscribe((accountProperty) => { + expect(accountProperty.accountProperties[0]!.address).to.be.equal(accountAddress); + done(); + }); + }); + }); + + describe('getAccountProperties', () => { + it('should call getAccountProperties successfully', (done) => { + accountHttp.getAccountProperties([accountAddress]).subscribe((accountProperties) => { + expect(accountProperties[0]!.accountProperties[0]!.address).to.be.equal(accountAddress); + done(); + }); + }); + }); describe('getMultisigAccountGraphInfo', () => { it('should call getMultisigAccountGraphInfo successfully', (done) => { accountHttp.getMultisigAccountGraphInfo(multisigPublicAccount.address).subscribe((multisigAccountGraphInfo) => { diff --git a/package-lock.json b/package-lock.json index b7c7cd3d7f..3070884359 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1213,20 +1213,20 @@ "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" }, "nem2-library": { - "version": "0.9.8", - "resolved": "https://registry.npmjs.org/nem2-library/-/nem2-library-0.9.8.tgz", - "integrity": "sha512-lijI3+bhH3TrpYqPyYuMUhks0Za26PsAg7dkIgNVNrYsgtMClx+RucaJ+r83MzwGJZGqgXEytb+XmL8zAUQyew==", + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/nem2-library/-/nem2-library-0.9.11.tgz", + "integrity": "sha512-FoTXkGQfx3gKd4w37zU+j9INdp9I/9qN8P7GEicuss3ikcGXxIwXv0rokME6x7FZUW0m17C3CkV0stAPZ1nk3w==", "requires": { - "bufferutil": "^3.0.5", + "bufferutil": "3.0.5", "crypto-browserify": "3.12.0", - "crypto-js": "^3.1.9-1", - "flatbuffers": "^1.7.0", - "js-sha3": "^0.6.1", - "lodash": "^4.17.10", - "ripemd160": "^2.0.1", - "superagent": "^3.8.3", - "utf-8-validate": "^4.0.2", - "ws": "^5.2.0" + "crypto-js": "3.1.9-1", + "flatbuffers": "1.10.2", + "js-sha3": "0.6.1", + "lodash": "4.17.11", + "ripemd160": "2.0.2", + "superagent": "3.8.3", + "utf-8-validate": "4.0.2", + "ws": "5.2.0" }, "dependencies": { "lodash": { diff --git a/package.json b/package.json index a5bab192ce..e5ac891d64 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@types/crypto-js": "^3.1.43", "crypto-js": "^3.1.9-1", "js-joda": "^1.6.2", - "nem2-library": "^0.9.8", + "nem2-library": "^0.9.11", "request": "^2.83.0", "request-promise-native": "^1.0.5", "rxjs": "^6.2.1", diff --git a/src/infrastructure/AccountHttp.ts b/src/infrastructure/AccountHttp.ts index aeaab3dce3..c2e2d02b53 100644 --- a/src/infrastructure/AccountHttp.ts +++ b/src/infrastructure/AccountHttp.ts @@ -18,6 +18,8 @@ import {AccountRoutesApi} from 'nem2-library'; import {from as observableFrom, Observable} from 'rxjs'; import {map, mergeMap} from 'rxjs/operators'; import {AccountInfo} from '../model/account/AccountInfo'; +import { AccountPropertiesInfo } from '../model/account/AccountPropertiesInfo'; +import { AccountProperty } from '../model/account/AccountProperty'; import {Address} from '../model/account/Address'; import {MultisigAccountGraphInfo} from '../model/account/MultisigAccountGraphInfo'; import {MultisigAccountInfo} from '../model/account/MultisigAccountInfo'; @@ -79,6 +81,38 @@ export class AccountHttp extends Http implements AccountRepository { })); } + /** + * Gets Account property. + * @param publicAccount public account + * @returns Observable + */ + public getAccountProperty(publicAccount: PublicAccount): Observable { + return observableFrom(this.accountRoutesApi.getAccountProperties(publicAccount.publicKey)).pipe(map((accountProperties) => { + return new AccountPropertiesInfo( + accountProperties.meta, + accountProperties.accountProperties, + ); + })); + } + + /** + * Gets Account properties. + * @param address list of addresses + * @returns Observable + */ + public getAccountProperties(addresses: Address[]): Observable { + const accountIds = addresses.map((address) => address.plain()); + return observableFrom( + this.accountRoutesApi.getAccountPropertiesFromAccounts(accountIds)).pipe(map((accountProperties) => { + return accountProperties.map((property) => { + return new AccountPropertiesInfo( + property.meta, + property.accountProperties, + ); + }); + })); + } + /** * Gets AccountsInfo for different accounts. * @param addresses List of Address @@ -160,8 +194,7 @@ export class AccountHttp extends Http implements AccountRepository { * @param queryParams - (Optional) Query params * @returns Observable */ - public transactions(publicAccount: PublicAccount, - queryParams?: QueryParams): Observable { + public transactions(publicAccount: PublicAccount, queryParams?: QueryParams): Observable { return observableFrom( this.accountRoutesApi.transactions(publicAccount.publicKey, queryParams != null ? queryParams : {})).pipe( map((transactionsDTO) => { @@ -178,8 +211,7 @@ export class AccountHttp extends Http implements AccountRepository { * @param queryParams - (Optional) Query params * @returns Observable */ - public incomingTransactions(publicAccount: PublicAccount, - queryParams?: QueryParams): Observable { + public incomingTransactions(publicAccount: PublicAccount, queryParams?: QueryParams): Observable { return observableFrom( this.accountRoutesApi.incomingTransactions(publicAccount.publicKey, queryParams != null ? queryParams : {})).pipe( map((transactionsDTO) => { @@ -196,8 +228,7 @@ export class AccountHttp extends Http implements AccountRepository { * @param queryParams - (Optional) Query params * @returns Observable */ - public outgoingTransactions(publicAccount: PublicAccount, - queryParams?: QueryParams): Observable { + public outgoingTransactions(publicAccount: PublicAccount, queryParams?: QueryParams): Observable { return observableFrom( this.accountRoutesApi.outgoingTransactions(publicAccount.publicKey, queryParams != null ? queryParams : {})).pipe( map((transactionsDTO) => { @@ -215,8 +246,7 @@ export class AccountHttp extends Http implements AccountRepository { * @param queryParams - (Optional) Query params * @returns Observable */ - public unconfirmedTransactions(publicAccount: PublicAccount, - queryParams?: QueryParams): Observable { + public unconfirmedTransactions(publicAccount: PublicAccount, queryParams?: QueryParams): Observable { return observableFrom( this.accountRoutesApi.unconfirmedTransactions(publicAccount.publicKey, queryParams != null ? queryParams : {})).pipe( map((transactionsDTO) => { @@ -233,9 +263,7 @@ export class AccountHttp extends Http implements AccountRepository { * @param queryParams - (Optional) Query params * @returns Observable */ - public aggregateBondedTransactions(publicAccount: PublicAccount, - queryParams?: QueryParams): Observable { - + public aggregateBondedTransactions(publicAccount: PublicAccount, queryParams?: QueryParams): Observable { return observableFrom( this.accountRoutesApi.partialTransactions(publicAccount.publicKey, queryParams != null ? queryParams : {})).pipe( map((transactionsDTO) => { diff --git a/src/infrastructure/transaction/CreateTransactionFromDTO.ts b/src/infrastructure/transaction/CreateTransactionFromDTO.ts index 50fdaef566..7d3f8010a0 100644 --- a/src/infrastructure/transaction/CreateTransactionFromDTO.ts +++ b/src/infrastructure/transaction/CreateTransactionFromDTO.ts @@ -17,6 +17,10 @@ import {Address} from '../../model/account/Address'; import {PublicAccount} from '../../model/account/PublicAccount'; import {NetworkType} from '../../model/blockchain/NetworkType'; +import { AccountPropertyModification, + ModifyAccountPropertyAddressTransaction, + ModifyAccountPropertyEntityTypeTransaction, + ModifyAccountPropertyMosaicTransaction } from '../../model/model'; import {Mosaic} from '../../model/mosaic/Mosaic'; import {MosaicId} from '../../model/mosaic/MosaicId'; import {MosaicProperties} from '../../model/mosaic/MosaicProperties'; @@ -254,6 +258,51 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr PublicAccount.createFromPublicKey(transactionDTO.signer, extractNetworkType(transactionDTO.version)), transactionInfo, ); + } else if (transactionDTO.type === TransactionType.MODIFY_ACCOUNT_PROPERTY_ADDRESS) { + return new ModifyAccountPropertyAddressTransaction( + extractNetworkType(transactionDTO.version), + extractTransactionVersion(transactionDTO.version), + Deadline.createFromDTO(transactionDTO.deadline), + new UInt64(transactionDTO.fee), + transactionDTO.propertyType, + transactionDTO.modifications ? transactionDTO.modifications.map((modificationDTO) => new AccountPropertyModification( + modificationDTO.modificationType, + modificationDTO.value, + )) : [], + transactionDTO.signature, + PublicAccount.createFromPublicKey(transactionDTO.signer, extractNetworkType(transactionDTO.version)), + transactionInfo, + ); + } else if (transactionDTO.type === TransactionType.MODIFY_ACCOUNT_PROPERTY_ENTITY_TYPE) { + return new ModifyAccountPropertyEntityTypeTransaction( + extractNetworkType(transactionDTO.version), + extractTransactionVersion(transactionDTO.version), + Deadline.createFromDTO(transactionDTO.deadline), + new UInt64(transactionDTO.fee), + transactionDTO.propertyType, + transactionDTO.modifications ? transactionDTO.modifications.map((modificationDTO) => new AccountPropertyModification( + modificationDTO.modificationType, + modificationDTO.value, + )) : [], + transactionDTO.signature, + PublicAccount.createFromPublicKey(transactionDTO.signer, extractNetworkType(transactionDTO.version)), + transactionInfo, + ); + } else if (transactionDTO.type === TransactionType.MODIFY_ACCOUNT_PROPERTY_MOSAIC) { + return new ModifyAccountPropertyMosaicTransaction( + extractNetworkType(transactionDTO.version), + extractTransactionVersion(transactionDTO.version), + Deadline.createFromDTO(transactionDTO.deadline), + new UInt64(transactionDTO.fee), + transactionDTO.propertyType, + transactionDTO.modifications ? transactionDTO.modifications.map((modificationDTO) => new AccountPropertyModification( + modificationDTO.modificationType, + modificationDTO.value, + )) : [], + transactionDTO.signature, + PublicAccount.createFromPublicKey(transactionDTO.signer, extractNetworkType(transactionDTO.version)), + transactionInfo, + ); } throw new Error('Unimplemented transaction with type ' + transactionDTO.type); diff --git a/src/model/account/AccountProperties.ts b/src/model/account/AccountProperties.ts new file mode 100644 index 0000000000..80035e71e8 --- /dev/null +++ b/src/model/account/AccountProperties.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { AccountProperty } from './AccountProperty'; +import { Address } from './Address'; +/** + * Account properties structure describes property information for an account. + */ +export class AccountProperties { + + /** + * Constructor + * @param address + * @param properties + */ + constructor( + /** + * Account Address + */ + public readonly address: Address, + /** + * Properties. + */ + public readonly properties: AccountProperty[]) { + + } +} diff --git a/src/model/account/AccountPropertiesInfo.ts b/src/model/account/AccountPropertiesInfo.ts new file mode 100644 index 0000000000..9e7060656e --- /dev/null +++ b/src/model/account/AccountPropertiesInfo.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { AccountProperties } from './AccountProperties'; +/** + * Account properties structure describes property information for an account. + */ +export class AccountPropertiesInfo { + + /** + * Constructor + * @param meta + * @param accountProperties + */ + constructor( + /** + * meta + */ + public readonly meta: any, + /** + * Properties. + */ + public readonly accountProperties: AccountProperties[]) { + + } +} diff --git a/src/model/account/AccountProperty.ts b/src/model/account/AccountProperty.ts new file mode 100644 index 0000000000..96774e1b9f --- /dev/null +++ b/src/model/account/AccountProperty.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PropertyType } from './PropertyType'; +/** + * Account property structure describes property information. + */ +export class AccountProperty { + + /** + * Constructor + * @param propertyType + * @param values + */ + constructor( + /** + * Account property type + */ + public readonly propertyType: PropertyType, + /** + * Property values. + */ + public readonly values: object[]) { + + } + +} diff --git a/src/model/account/PropertyModificationType.ts b/src/model/account/PropertyModificationType.ts new file mode 100644 index 0000000000..6ba3b7d9db --- /dev/null +++ b/src/model/account/PropertyModificationType.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Account property modification type + */ +export enum PropertyModificationType { + Add = 0x00, + Remove = 0x01, +} diff --git a/src/model/account/PropertyType.ts b/src/model/account/PropertyType.ts new file mode 100644 index 0000000000..1b13f72113 --- /dev/null +++ b/src/model/account/PropertyType.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Account property type + * 0x01 The property type is an address. + * 0x02 The property type is mosaic id. + * 0x03 The property type is a transaction type. + * 0x04 Property type sentinel. + * 0x80 + type The property is interpreted as a blocking operation. + */ + +export enum PropertyType { + AllowAddress = 0x01, + AllowMosaic = 0x02, + AllowTransaction = 0x04, + Sentinel = 0x05, + BlockAddress = (0x80 + 0x01), + BlockMosaic = (0x80 + 0x02), + BlockTransaction = (0x80 + 0x04), +} diff --git a/src/model/model.ts b/src/model/model.ts index dfb6b3e733..a71ceba84f 100644 --- a/src/model/model.ts +++ b/src/model/model.ts @@ -24,6 +24,11 @@ export * from './account/Address'; export * from './account/MultisigAccountGraphInfo'; export * from './account/MultisigAccountInfo'; export * from './account/PublicAccount'; +export * from './account/AccountProperties'; +export * from './account/AccountPropertiesInfo'; +export * from './account/AccountProperty'; +export * from './account/PropertyModificationType'; +export * from './account/PropertyType'; // Blockchain export * from './blockchain/BlockchainScore'; @@ -56,6 +61,11 @@ export * from './namespace/NamespaceType'; export * from './namespace/AliasActionType'; // Transaction +export * from './transaction/AccountPropertyTransaction'; +export * from './transaction/ModifyAccountPropertyAddressTransaction'; +export * from './transaction/ModifyAccountPropertyEntityTypeTransaction'; +export * from './transaction/ModifyAccountPropertyMosaicTransaction'; +export * from './transaction/AccountPropertyModification'; export * from './transaction/AddressAliasTransaction'; export * from './transaction/AggregateTransaction'; export * from './transaction/AggregateTransactionCosignature'; diff --git a/src/model/transaction/AccountPropertyModification.ts b/src/model/transaction/AccountPropertyModification.ts new file mode 100644 index 0000000000..98546adbe5 --- /dev/null +++ b/src/model/transaction/AccountPropertyModification.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PropertyModificationType } from '../account/PropertyModificationType'; + +export class AccountPropertyModification { + + /** + * Constructor + * @param modificationType + * @param value + */ + constructor( + /** + * Modification type. + */ + public readonly modificationType: PropertyModificationType, + /** + * Modification value (Address, Mosaic or Transaction Type). + */ + public readonly value: T) { + + } + + /** + * @internal + */ + toDTO() { + return { + value: this.value, + modificationType: this.modificationType, + }; + } +} diff --git a/src/model/transaction/AccountPropertyTransaction.ts b/src/model/transaction/AccountPropertyTransaction.ts new file mode 100644 index 0000000000..b794365da6 --- /dev/null +++ b/src/model/transaction/AccountPropertyTransaction.ts @@ -0,0 +1,115 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NetworkType } from '../blockchain/NetworkType'; +import { AccountPropertyModification, + Address, + ModifyAccountPropertyAddressTransaction, + ModifyAccountPropertyEntityTypeTransaction, + ModifyAccountPropertyMosaicTransaction, + PropertyModificationType, PropertyType } from '../model'; +import { MosaicId } from '../mosaic/MosaicId'; +import { Deadline } from './Deadline'; +import { TransactionType } from './TransactionType'; + +export class AccountPropertyTransaction { + /** + * Create an address modification transaction object + * @param deadline - The deadline to include the transaction. + * @param propertyType - Type of account property transaction + * @param modification - array of address modifications + * @param networkType - The network type. + * @returns {ModifyAccountPropertyAddressTransaction} + */ + public static createAddressPropertyModificationTransaction(deadline: Deadline, + propertyType: PropertyType, + modifications: Array>, + networkType: NetworkType): ModifyAccountPropertyAddressTransaction { + if (![PropertyType.AllowAddress, PropertyType.BlockAddress].includes(propertyType)) { + throw new Error ('Property type is not allowed.'); + } + return ModifyAccountPropertyAddressTransaction.create(deadline, propertyType, modifications, networkType); + } + + /** + * Create an mosaic modification transaction object + * @param deadline - The deadline to include the transaction. + * @param propertyType - Type of account property transaction + * @param modification - array of mosaic modifications + * @param networkType - The network type. + * @returns {ModifyAccountPropertyMosaicTransaction} + */ + public static createMosaicPropertyModificationTransaction(deadline: Deadline, + propertyType: PropertyType, + modifications: Array>, + networkType: NetworkType): ModifyAccountPropertyMosaicTransaction { + if (![PropertyType.AllowMosaic, PropertyType.BlockMosaic].includes(propertyType)) { + throw new Error ('Property type is not allowed.'); + } + return ModifyAccountPropertyMosaicTransaction.create(deadline, propertyType, modifications, networkType); + } + + /** + * Create an entity type modification transaction object + * @param deadline - The deadline to include the transaction. + * @param propertyType - Type of account property transaction + * @param modification - array of entity type modifications + * @param networkType - The network type. + * @returns {ModifyAccountPropertyEntityTypeTransaction} + */ + public static createEntityTypePropertyModificationTransaction(deadline: Deadline, + propertyType: PropertyType, + modifications: Array>, + networkType: NetworkType): ModifyAccountPropertyEntityTypeTransaction { + if (![PropertyType.AllowTransaction, PropertyType.BlockTransaction].includes(propertyType)) { + throw new Error ('Property type is not allowed.'); + } + return ModifyAccountPropertyEntityTypeTransaction.create(deadline, propertyType, modifications, networkType); + } + + /** + * Create an address filter for account property modification + * @param modificationType - modification type. 0: Add, 1: Remove + * @param address - modification value (Address) + * @returns {AccountPropertyModification} + */ + public static createAddressFilter(modificationType: PropertyModificationType, + address: Address): AccountPropertyModification { + return new AccountPropertyModification(modificationType, address.plain()); + } + + /** + * Create an mosaic filter for account property modification + * @param modificationType - modification type. 0: Add, 1: Remove + * @param mosaicId - modification value (Mosaic) + * @returns {AccountPropertyModification} + */ + public static createMosaicFilter(modificationType: PropertyModificationType, + mosaicId: MosaicId): AccountPropertyModification { + return new AccountPropertyModification(modificationType, mosaicId.id.toDTO()); + } + + /** + * Create an entity type filter for account property modification + * @param modificationType - modification type. 0: Add, 1: Remove + * @param entityType - modification value (Transaction Type) + * @returns {AccountPropertyModification} + */ + public static createEntityTypeFilter(modificationType: PropertyModificationType, + entityType: number): AccountPropertyModification { + return new AccountPropertyModification(modificationType, entityType); + } +} diff --git a/src/model/transaction/ModifyAccountPropertyAddressTransaction.ts b/src/model/transaction/ModifyAccountPropertyAddressTransaction.ts new file mode 100644 index 0000000000..b275879711 --- /dev/null +++ b/src/model/transaction/ModifyAccountPropertyAddressTransaction.ts @@ -0,0 +1,89 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AccountPropertiesAddressTransaction as AccountPropertiesAddressTransactionLibrary, VerifiableTransaction } from 'nem2-library'; +import { PropertyType } from '../account/PropertyType'; +import { PublicAccount } from '../account/PublicAccount'; +import { NetworkType } from '../blockchain/NetworkType'; +import { UInt64 } from '../UInt64'; +import { AccountPropertyModification } from './AccountPropertyModification'; +import { Deadline } from './Deadline'; +import { Transaction } from './Transaction'; +import { TransactionInfo } from './TransactionInfo'; +import { TransactionType } from './TransactionType'; +import { TransactionVersion } from './TransactionVersion'; + +export class ModifyAccountPropertyAddressTransaction extends Transaction { + + /** + * Create a modify account property address transaction object + * @param deadline - The deadline to include the transaction. + * @param propertyType - The account property type. + * @param modifications - The array of modifications. + * @param networkType - The network type. + * @returns {ModifyAccountPropertyAddressTransaction} + */ + public static create(deadline: Deadline, + propertyType: PropertyType, + modifications: Array>, + networkType: NetworkType): ModifyAccountPropertyAddressTransaction { + return new ModifyAccountPropertyAddressTransaction(networkType, + TransactionVersion.MODIFY_ACCOUNT_PROPERTY_ADDRESS, + deadline, + new UInt64([0, 0]), + propertyType, + modifications); + } + + /** + * @param networkType + * @param version + * @param deadline + * @param fee + * @param minApprovalDelta + * @param minRemovalDelta + * @param modifications + * @param signature + * @param signer + * @param transactionInfo + */ + constructor(networkType: NetworkType, + version: number, + deadline: Deadline, + fee: UInt64, + public readonly propertyType: PropertyType, + public readonly modifications: Array>, + signature?: string, + signer?: PublicAccount, + transactionInfo?: TransactionInfo) { + super(TransactionType.MODIFY_ACCOUNT_PROPERTY_ADDRESS, networkType, version, deadline, fee, signature, signer, transactionInfo); + } + + /** + * @internal + * @returns {VerifiableTransaction} + */ + protected buildTransaction(): VerifiableTransaction { + return new AccountPropertiesAddressTransactionLibrary.Builder() + .addDeadline(this.deadline.toDTO()) + .addFee(this.fee.toDTO()) + .addVersion(this.versionToDTO()) + .addPropertyType(this.propertyType) + .addModifications(this.modifications.map((modification) => modification.toDTO())) + .build(); + } + +} diff --git a/src/model/transaction/ModifyAccountPropertyEntityTypeTransaction.ts b/src/model/transaction/ModifyAccountPropertyEntityTypeTransaction.ts new file mode 100644 index 0000000000..5143c50724 --- /dev/null +++ b/src/model/transaction/ModifyAccountPropertyEntityTypeTransaction.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AccountPropertiesEntityTypeTransaction as AccountPropertiesEntityTypeTransactionLibrary, + VerifiableTransaction } from 'nem2-library'; +import { PropertyType } from '../account/PropertyType'; +import { PublicAccount } from '../account/PublicAccount'; +import { NetworkType } from '../blockchain/NetworkType'; +import { UInt64 } from '../UInt64'; +import { AccountPropertyModification } from './AccountPropertyModification'; +import { Deadline } from './Deadline'; +import { Transaction } from './Transaction'; +import { TransactionInfo } from './TransactionInfo'; +import { TransactionType } from './TransactionType'; +import { TransactionVersion } from './TransactionVersion'; + +export class ModifyAccountPropertyEntityTypeTransaction extends Transaction { + + /** + * Create a modify account property entity type transaction object + * @param deadline - The deadline to include the transaction. + * @param propertyType - The account property type. + * @param modifications - The array of modifications. + * @param networkType - The network type. + * @returns {ModifyAccountPropertyEntityTypeTransaction} + */ + public static create(deadline: Deadline, + propertyType: PropertyType, + modifications: Array>, + networkType: NetworkType): ModifyAccountPropertyEntityTypeTransaction { + return new ModifyAccountPropertyEntityTypeTransaction(networkType, + TransactionVersion.MODIFY_ACCOUNT_PROPERTY_ENTITY_TYPE, + deadline, + new UInt64([0, 0]), + propertyType, + modifications); + } + + /** + * @param networkType + * @param version + * @param deadline + * @param fee + * @param minApprovalDelta + * @param minRemovalDelta + * @param modifications + * @param signature + * @param signer + * @param transactionInfo + */ + constructor(networkType: NetworkType, + version: number, + deadline: Deadline, + fee: UInt64, + public readonly propertyType: PropertyType, + public readonly modifications: Array>, + signature?: string, + signer?: PublicAccount, + transactionInfo?: TransactionInfo) { + super(TransactionType.MODIFY_ACCOUNT_PROPERTY_ENTITY_TYPE, networkType, version, deadline, fee, signature, signer, transactionInfo); + } + + /** + * @internal + * @returns {VerifiableTransaction} + */ + protected buildTransaction(): VerifiableTransaction { + return new AccountPropertiesEntityTypeTransactionLibrary.Builder() + .addDeadline(this.deadline.toDTO()) + .addFee(this.fee.toDTO()) + .addVersion(this.versionToDTO()) + .addPropertyType(this.propertyType) + .addModifications(this.modifications.map((modification) => modification.toDTO())) + .build(); + } + +} diff --git a/src/model/transaction/ModifyAccountPropertyMosaicTransaction.ts b/src/model/transaction/ModifyAccountPropertyMosaicTransaction.ts new file mode 100644 index 0000000000..a0fe94eda7 --- /dev/null +++ b/src/model/transaction/ModifyAccountPropertyMosaicTransaction.ts @@ -0,0 +1,89 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AccountPropertiesMosaicTransaction as AccountPropertiesMosaicTransactionLibrary, VerifiableTransaction } from 'nem2-library'; +import { PropertyType } from '../account/PropertyType'; +import { PublicAccount } from '../account/PublicAccount'; +import { NetworkType } from '../blockchain/NetworkType'; +import { UInt64 } from '../UInt64'; +import { AccountPropertyModification } from './AccountPropertyModification'; +import { Deadline } from './Deadline'; +import { Transaction } from './Transaction'; +import { TransactionInfo } from './TransactionInfo'; +import { TransactionType } from './TransactionType'; +import { TransactionVersion } from './TransactionVersion'; + +export class ModifyAccountPropertyMosaicTransaction extends Transaction { + + /** + * Create a modify account property mosaic transaction object + * @param deadline - The deadline to include the transaction. + * @param propertyType - The account property type. + * @param modifications - The array of modifications. + * @param networkType - The network type. + * @returns {ModifyAccountPropertyAddressTransaction} + */ + public static create(deadline: Deadline, + propertyType: PropertyType, + modifications: Array>, + networkType: NetworkType): ModifyAccountPropertyMosaicTransaction { + return new ModifyAccountPropertyMosaicTransaction(networkType, + TransactionVersion.MODIFY_ACCOUNT_PROPERTY_MOSAIC, + deadline, + new UInt64([0, 0]), + propertyType, + modifications); + } + + /** + * @param networkType + * @param version + * @param deadline + * @param fee + * @param minApprovalDelta + * @param minRemovalDelta + * @param modifications + * @param signature + * @param signer + * @param transactionInfo + */ + constructor(networkType: NetworkType, + version: number, + deadline: Deadline, + fee: UInt64, + public readonly propertyType: PropertyType, + public readonly modifications: Array>, + signature?: string, + signer?: PublicAccount, + transactionInfo?: TransactionInfo) { + super(TransactionType.MODIFY_ACCOUNT_PROPERTY_MOSAIC, networkType, version, deadline, fee, signature, signer, transactionInfo); + } + + /** + * @internal + * @returns {VerifiableTransaction} + */ + protected buildTransaction(): VerifiableTransaction { + return new AccountPropertiesMosaicTransactionLibrary.Builder() + .addDeadline(this.deadline.toDTO()) + .addFee(this.fee.toDTO()) + .addVersion(this.versionToDTO()) + .addPropertyType(this.propertyType) + .addModifications(this.modifications.map((modification) => modification.toDTO())) + .build(); + } + +} diff --git a/src/model/transaction/TransactionType.ts b/src/model/transaction/TransactionType.ts index e12f050883..81cd813716 100644 --- a/src/model/transaction/TransactionType.ts +++ b/src/model/transaction/TransactionType.ts @@ -89,4 +89,22 @@ export class TransactionType { * @type {number} */ public static readonly SECRET_PROOF = 0x4252; + + /** + * Account property address transaction type + * @type {number} + */ + public static readonly MODIFY_ACCOUNT_PROPERTY_ADDRESS = 0x4150; + + /** + * Account property mosaic transaction type + * @type {number} + */ + public static readonly MODIFY_ACCOUNT_PROPERTY_MOSAIC = 0x4250; + + /** + * Account property entity type transaction type + * @type {number} + */ + public static readonly MODIFY_ACCOUNT_PROPERTY_ENTITY_TYPE = 0x4350; } diff --git a/src/model/transaction/TransactionVersion.ts b/src/model/transaction/TransactionVersion.ts index a1f0d3b580..7dcedcc9f9 100644 --- a/src/model/transaction/TransactionVersion.ts +++ b/src/model/transaction/TransactionVersion.ts @@ -19,10 +19,10 @@ * * Transaction format versions are defined in catapult-server in * each transaction's plugin source code. - * + * * In [catapult-server](https://github.com/nemtech/catapult-server), the `DEFINE_TRANSACTION_CONSTANTS` macro * is used to define the `TYPE` and `VERSION` of the transaction format. - * + * * @see https://github.com/nemtech/catapult-server/blob/master/plugins/txes/transfer/src/model/TransferTransaction.h#L37 */ export class TransactionVersion { @@ -97,4 +97,22 @@ export class TransactionVersion { * @type {number} */ public static readonly MOSAIC_ALIAS = 1; + + /** + * Account Property address transaction version + * @type {number} + */ + public static readonly MODIFY_ACCOUNT_PROPERTY_ADDRESS = 1; + + /** + * Account Property mosaic transaction version + * @type {number} + */ + public static readonly MODIFY_ACCOUNT_PROPERTY_MOSAIC = 1; + + /** + * Account Property entity type transaction version + * @type {number} + */ + public static readonly MODIFY_ACCOUNT_PROPERTY_ENTITY_TYPE = 1; } diff --git a/test/model/account/AccountProperties.spec.ts b/test/model/account/AccountProperties.spec.ts new file mode 100644 index 0000000000..0ffbf09aae --- /dev/null +++ b/test/model/account/AccountProperties.spec.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2018 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {deepEqual} from 'assert'; +import {expect} from 'chai'; +import {Address} from '../../../src/model/account/Address'; +import { AccountProperties, PropertyModificationType, PropertyType } from '../../../src/model/model'; + +describe('AccountProperties', () => { + + it('should createComplete an AccountProperties object', () => { + const accountPropertiesDTO = { + address: Address.createFromEncoded('9050B9837EFAB4BBE8A4B9BB32D812F9885C00D8FC1650E142'), + properties: [{ + propertyType: PropertyType.AllowAddress, + values: [{modificationType: PropertyModificationType.Add, + value: 'SDUP5PLHDXKBX3UU5Q52LAY4WYEKGEWC6IB3VBFM', + }], + }], + }; + + const accountProperties = new AccountProperties( + accountPropertiesDTO.address, + accountPropertiesDTO.properties, + ); + + expect(accountProperties.address).to.be.equal(accountPropertiesDTO.address); + deepEqual(accountPropertiesDTO.properties.length, accountPropertiesDTO.properties.length); + deepEqual(accountPropertiesDTO.properties[0].propertyType, accountPropertiesDTO.properties[0].propertyType); + deepEqual(accountPropertiesDTO.properties[0].values.length, accountPropertiesDTO.properties[0].values.length); + deepEqual(accountPropertiesDTO.properties[0].values[0].modificationType, + accountPropertiesDTO.properties[0].values[0].modificationType); + deepEqual(accountPropertiesDTO.properties[0].values[0].value, accountPropertiesDTO.properties[0].values[0].value); + }); +}); diff --git a/test/model/account/AccountPropertiesInfo.spec.ts b/test/model/account/AccountPropertiesInfo.spec.ts new file mode 100644 index 0000000000..6653ce831e --- /dev/null +++ b/test/model/account/AccountPropertiesInfo.spec.ts @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {deepEqual} from 'assert'; +import {Address} from '../../../src/model/account/Address'; +import {AccountPropertiesInfo, PropertyModificationType, PropertyType } from '../../../src/model/model'; + +describe('AccountPropertiesInfo', () => { + + it('should createComplete an AccountPropertiesInfo object', () => { + + const accountPropertiesInfoDTO = { + meta: {id: '12345'}, + accountProperties: [{ + address: Address.createFromEncoded('9050B9837EFAB4BBE8A4B9BB32D812F9885C00D8FC1650E142'), + properties: [{ + propertyType: PropertyType.AllowAddress, + values: [{modificationType: PropertyModificationType.Add, + value: 'SDUP5PLHDXKBX3UU5Q52LAY4WYEKGEWC6IB3VBFM', + }], + }], + }], + }; + + const accountPropertiesInfo = new AccountPropertiesInfo( + accountPropertiesInfoDTO.meta, + accountPropertiesInfoDTO.accountProperties, + ); + + deepEqual(accountPropertiesInfo.meta.id, accountPropertiesInfoDTO.meta.id); + deepEqual(accountPropertiesInfo.accountProperties.length, accountPropertiesInfoDTO.accountProperties.length); + deepEqual(accountPropertiesInfo.accountProperties[0].address, accountPropertiesInfoDTO.accountProperties[0].address); + deepEqual(accountPropertiesInfo.accountProperties[0].properties.length, + accountPropertiesInfoDTO.accountProperties[0].properties.length); + deepEqual(accountPropertiesInfo.accountProperties[0].properties[0].values[0], + accountPropertiesInfoDTO.accountProperties[0].properties[0].values[0]); + }); +}); diff --git a/test/model/account/AccountProperty.spec.ts b/test/model/account/AccountProperty.spec.ts new file mode 100644 index 0000000000..9974b0243e --- /dev/null +++ b/test/model/account/AccountProperty.spec.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {deepEqual} from 'assert'; +import {expect} from 'chai'; +import { AccountProperty, PropertyModificationType, PropertyType } from '../../../src/model/model'; + +describe('AccountProperty', () => { + + it('should createComplete an AccountProperty object', () => { + const accountPropertyDTO = { + propertyType: PropertyType.AllowAddress, + values: [{modificationType: PropertyModificationType.Add, + value: 'SDUP5PLHDXKBX3UU5Q52LAY4WYEKGEWC6IB3VBFM', + }], + }; + + const accountProperty = new AccountProperty( + accountPropertyDTO.propertyType, + accountPropertyDTO.values, + ); + + expect(accountProperty.propertyType).to.be.equal(accountPropertyDTO.propertyType); + deepEqual(accountProperty.values.length, accountPropertyDTO.values.length); + }); +}); diff --git a/test/model/transaction/AccountPropertyTransaction.spec.ts b/test/model/transaction/AccountPropertyTransaction.spec.ts new file mode 100644 index 0000000000..f6a5bb473e --- /dev/null +++ b/test/model/transaction/AccountPropertyTransaction.spec.ts @@ -0,0 +1,170 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {expect} from 'chai'; +import {Account} from '../../../src/model/account/Account'; +import {Address} from '../../../src/model/account/Address'; +import {NetworkType} from '../../../src/model/blockchain/NetworkType'; +import { PropertyModificationType, PropertyType, TransactionType } from '../../../src/model/model'; +import {MosaicId} from '../../../src/model/mosaic/MosaicId'; +import {AccountPropertyTransaction} from '../../../src/model/transaction/AccountPropertyTransaction'; +import {Deadline} from '../../../src/model/transaction/Deadline'; +import {TestingAccount} from '../../conf/conf.spec'; + +describe('AccountPropertyTransaction', () => { + let account: Account; + + before(() => { + account = TestingAccount; + }); + it('should create address property filter', () => { + const address = Address.createFromRawAddress('SBILTA367K2LX2FEXG5TFWAS7GEFYAGY7QLFBYKC'); + const addressPropertyFilter = AccountPropertyTransaction.createAddressFilter( + PropertyModificationType.Add, + address, + ); + expect(addressPropertyFilter.modificationType).to.be.equal(PropertyModificationType.Add); + expect(addressPropertyFilter.value).to.be.equal(address.plain()); + }); + + it('should create mosaic property filter', () => { + const mosaicId = new MosaicId([2262289484, 3405110546]); + const mosaicPropertyFilter = AccountPropertyTransaction.createMosaicFilter( + PropertyModificationType.Add, + mosaicId, + ); + expect(mosaicPropertyFilter.modificationType).to.be.equal(PropertyModificationType.Add); + expect(mosaicPropertyFilter.value[0]).to.be.equal(mosaicId.id.lower); + expect(mosaicPropertyFilter.value[1]).to.be.equal(mosaicId.id.higher); + }); + + it('should create entity type property filter', () => { + const entityType = TransactionType.ADDRESS_ALIAS; + const entityTypePropertyFilter = AccountPropertyTransaction.createEntityTypeFilter( + PropertyModificationType.Add, + entityType, + ); + expect(entityTypePropertyFilter.modificationType).to.be.equal(PropertyModificationType.Add); + expect(entityTypePropertyFilter.value).to.be.equal(entityType); + }); + + it('should create address property transaction', () => { + + const address = Address.createFromRawAddress('SBILTA367K2LX2FEXG5TFWAS7GEFYAGY7QLFBYKC'); + const addressPropertyFilter = AccountPropertyTransaction.createAddressFilter( + PropertyModificationType.Add, + address, + ); + const addressPropertyTransaction = AccountPropertyTransaction.createAddressPropertyModificationTransaction( + Deadline.create(), + PropertyType.AllowAddress, + [addressPropertyFilter], + NetworkType.MIJIN_TEST, + ); + + const signedTransaction = addressPropertyTransaction.signWith(account); + + expect(signedTransaction.payload.substring( + 240, + signedTransaction.payload.length, + )).to.be.equal('0101009050B9837EFAB4BBE8A4B9BB32D812F9885C00D8FC1650E142'); + + }); + + it('should throw exception when create address property transaction with wrong type', () => { + + const address = Address.createFromRawAddress('SBILTA367K2LX2FEXG5TFWAS7GEFYAGY7QLFBYKC'); + const addressPropertyFilter = AccountPropertyTransaction.createAddressFilter( + PropertyModificationType.Add, + address, + ); + + expect(() => { + AccountPropertyTransaction.createAddressPropertyModificationTransaction( + Deadline.create(), + PropertyType.Sentinel, + [addressPropertyFilter], + NetworkType.MIJIN_TEST, + ); + }).to.throw(Error, 'Property type is not allowed.'); + + }); + + it('should create mosaic property transaction', () => { + + const mosaicId = new MosaicId([2262289484, 3405110546]); + const mosaicPropertyFilter = AccountPropertyTransaction.createMosaicFilter( + PropertyModificationType.Add, + mosaicId, + ); + const mosaicPropertyTransaction = AccountPropertyTransaction.createMosaicPropertyModificationTransaction( + Deadline.create(), + PropertyType.AllowMosaic, + [mosaicPropertyFilter], + NetworkType.MIJIN_TEST, + ); + + const signedTransaction = mosaicPropertyTransaction.signWith(account); + + expect(signedTransaction.payload.substring( + 240, + signedTransaction.payload.length, + )).to.be.equal('0201004CCCD78612DDF5CA'); + + }); + + it('should throw exception when create mosaic property transaction with wrong type', () => { + + const mosaicId = new MosaicId([2262289484, 3405110546]); + const mosaicPropertyFilter = AccountPropertyTransaction.createMosaicFilter( + PropertyModificationType.Add, + mosaicId, + ); + + expect(() => { + AccountPropertyTransaction.createMosaicPropertyModificationTransaction( + Deadline.create(), + PropertyType.Sentinel, + [mosaicPropertyFilter], + NetworkType.MIJIN_TEST, + ); + }).to.throw(Error, 'Property type is not allowed.'); + + }); + + it('should create entity type property transaction', () => { + + const entityType = TransactionType.ADDRESS_ALIAS; + const entityTypePropertyFilter = AccountPropertyTransaction.createEntityTypeFilter( + PropertyModificationType.Add, + entityType, + ); + const entityTypePropertyTransaction = AccountPropertyTransaction.createEntityTypePropertyModificationTransaction( + Deadline.create(), + PropertyType.AllowTransaction, + [entityTypePropertyFilter], + NetworkType.MIJIN_TEST, + ); + + const signedTransaction = entityTypePropertyTransaction.signWith(account); + + expect(signedTransaction.payload.substring( + 240, + signedTransaction.payload.length, + )).to.be.equal('0401004E42'); + + }); +});