Skip to content

Commit f3ea076

Browse files
author
Grégory Saive
authored
Merge pull request #91 from evias/task/G89/alias-in-transaction
Fix issue #89: Read recipient from encoded hexadecimal notation
2 parents 29193b9 + be87013 commit f3ea076

File tree

6 files changed

+97
-10
lines changed

6 files changed

+97
-10
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nem2-sdk",
3-
"version": "0.11.0",
3+
"version": "0.11.1",
44
"description": "Reactive Nem2 sdk for typescript and javascript",
55
"scripts": {
66
"pretest": "npm run build",

src/infrastructure/transaction/CreateTransactionFromDTO.ts

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
16+
import {convert} from 'nem2-library';
17+
import {uint64 as UInt64Library} from 'nem2-library';
1718
import {Address} from '../../model/account/Address';
1819
import {PublicAccount} from '../../model/account/PublicAccount';
1920
import {NetworkType} from '../../model/blockchain/NetworkType';
21+
import {Id} from '../../model/Id';
2022
import {Mosaic} from '../../model/mosaic/Mosaic';
2123
import {MosaicId} from '../../model/mosaic/MosaicId';
2224
import {MosaicProperties} from '../../model/mosaic/MosaicProperties';
@@ -121,10 +123,8 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr
121123
extractTransactionVersion(transactionDTO.version),
122124
Deadline.createFromDTO(transactionDTO.deadline),
123125
new UInt64(transactionDTO.fee || [0, 0]),
124-
Address.createFromEncoded(transactionDTO.recipient),
125-
transactionDTO.mosaics === undefined ? [] :
126-
transactionDTO.mosaics
127-
.map((mosaicDTO) => new Mosaic(new MosaicId(mosaicDTO.id), new UInt64(mosaicDTO.amount))),
126+
extractRecipient(transactionDTO.recipient),
127+
extractMosaics(transactionDTO.mosaics),
128128
transactionDTO.message !== undefined ?
129129
PlainMessage.createFromDTO(transactionDTO.message.payload) : EmptyMessage,
130130
transactionDTO.signature,
@@ -339,3 +339,60 @@ const extractNetworkType = (version: number): NetworkType => {
339339
const extractTransactionVersion = (version: number): number => {
340340
return parseInt(version.toString(16).substr(2, 2), 16);
341341
};
342+
343+
/**
344+
* Extract recipient value from encoded hexadecimal notation.
345+
*
346+
* If bit 0 of byte 0 is not set (e.g. 0x90), then it is a regular address.
347+
* Else (e.g. 0x91) it represents a namespace id which starts at byte 1.
348+
*
349+
* @param recipient {string} Encoded hexadecimal recipient notation
350+
* @return {Address | NamespaceId}
351+
*/
352+
const extractRecipient = (recipient: string): Address | NamespaceId => {
353+
// If bit 0 of byte 0 is not set (like in 0x90), then it is a regular address.
354+
// Else (e.g. 0x91) it represents a namespace id which starts at byte 1.
355+
const bit0 = convert.hexToUint8(recipient.substr(1, 2))[0];
356+
357+
if ((bit0 & 16) === 16) {
358+
// namespaceId encoded hexadecimal notation provided
359+
// only 8 bytes are relevant to resolve the NamespaceId
360+
const relevantPart = recipient.substr(2, 16);
361+
return NamespaceId.createFromEncoded(relevantPart);
362+
}
363+
364+
// read address from encoded hexadecimal notation
365+
return Address.createFromEncoded(recipient);
366+
};
367+
368+
/**
369+
* Extract mosaics from encoded UInt64 notation.
370+
*
371+
* If most significant bit of byte 0 is set, then it is a namespaceId.
372+
* If most significant bit of byte 0 is not set, then it is a mosaicId.
373+
*
374+
* @param mosaics {Array | undefined} The DTO array of mosaics (with UInt64 Id notation)
375+
* @return {Mosaic[]}
376+
*/
377+
const extractMosaics = (mosaics: any): Mosaic[] => {
378+
379+
if (mosaics === undefined) {
380+
return [];
381+
}
382+
383+
return mosaics.map((mosaicDTO) => {
384+
385+
// convert ID to UInt8 bytes array and get first byte (most significant byte)
386+
const uint64 = new Id(mosaicDTO.id);
387+
const bytes = convert.hexToUint8(UInt64Library.toHex(uint64.toDTO()));
388+
const byte0 = bytes[0];
389+
390+
// if most significant bit of byte 0 is set, then we have a namespaceId
391+
if ((byte0 & 128) === 128) {
392+
return new Mosaic(new NamespaceId(mosaicDTO.id), new UInt64(mosaicDTO.amount));
393+
}
394+
395+
// most significant bit of byte 0 is not set => mosaicId
396+
return new Mosaic(new MosaicId(mosaicDTO.id), new UInt64(mosaicDTO.amount));
397+
});
398+
};

src/model/namespace/NamespaceId.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
import {namespaceId as NamespaceIdGenerator} from 'nem2-library';
16+
import {convert, namespaceId as NamespaceIdGenerator} from 'nem2-library';
1717
import {Id} from '../Id';
1818

1919
/**
@@ -48,6 +48,18 @@ export class NamespaceId {
4848
}
4949
}
5050

51+
/**
52+
* Create a NamespaceId object from its encoded hexadecimal notation.
53+
* @param encoded
54+
* @returns {NamespaceId}
55+
*/
56+
public static createFromEncoded(encoded: string): NamespaceId {
57+
const uint = convert.hexToUint8(encoded).reverse();
58+
const hex = convert.uint8ToHex(uint);
59+
const namespace = new NamespaceId(Id.fromHex(hex).toDTO());
60+
return namespace;
61+
}
62+
5163
/**
5264
* Get string value of id
5365
* @returns {string}

src/model/transaction/TransferTransaction.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,13 @@ export class TransferTransaction extends Transaction {
9595
* @returns {string}
9696
*/
9797
public recipientToString(): string {
98+
9899
if (this.recipient instanceof NamespaceId) {
99-
// namespaceId available, return hexadecimal notation
100+
// namespaceId recipient, return hexadecimal notation
100101
return (this.recipient as NamespaceId).toHex();
101102
}
102103

103-
// address available
104+
// address recipient
104105
return (this.recipient as Address).plain();
105106
}
106107

test/model/namespace/NamespaceId.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,21 @@ describe('NamespaceId', () => {
3737
deepEqual(id.id, new Id([3646934825, 3576016193]));
3838
expect(id.fullName).to.be.equal(undefined);
3939
});
40+
41+
const vectors = [
42+
{encoded: '4bfa5f372d55b384', uint: [929036875, 2226345261]}, // new NamespaceId('nem')
43+
{encoded: '08a12f89ee5a49f8', uint: [2301600008, 4165556974]}, // new NamespaceId('nem.owner.test1')
44+
{encoded: '1f810565e8f4aeab', uint: [1694859551, 2880369896]}, // new NamespaceId('nem.owner.test2')
45+
{encoded: '552d1c0a2bc9b8ae', uint: [169618773, 2931345707]}, // new NamespaceId('nem.owner.test3')
46+
{encoded: 'bfca1440d49ae090', uint: [1075104447, 2430638804]}, // new NamespaceId('nem.owner.test4')
47+
{encoded: 'ccf10b96814211ab', uint: [2517365196, 2870035073]}, // new NamespaceId('nem.owner.test5')
48+
];
49+
50+
it('should be created from encoded vectors', () => {
51+
vectors.map(({encoded, uint}) => {
52+
const fromHex = NamespaceId.createFromEncoded(encoded.toUpperCase());
53+
const fromId = new NamespaceId(uint);
54+
deepEqual(fromId.id, fromHex.id);
55+
});
56+
});
4057
});

0 commit comments

Comments
 (0)