Skip to content

Allow rest base 32 addresses #804

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/core/utils/DtoMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { MerkleTreeBranch } from '../../model/state/MerkleTreeBranch';
import { MerkleTreeBranchLink } from '../../model/state/MerkleTreeBranchLink';
import { MerkleTreeLeaf } from '../../model/state/MerkleTreeLeaf';
import { MerkleTreeNodeType } from '../../model/state/MerkleTreeNodeType';
import { Convert } from '../format';

export class DtoMapping {
/**
Expand All @@ -45,7 +46,7 @@ export class DtoMapping {
return new AccountRestrictions(
accountRestrictions.accountRestrictions.version || 1,
accountRestrictions['id'],
Address.createFromEncoded(accountRestrictions.accountRestrictions.address),
DtoMapping.toAddress(accountRestrictions.accountRestrictions.address),
accountRestrictions.accountRestrictions.restrictions.map((prop) => {
const restrictionFlags = prop.restrictionFlags as number;
switch (restrictionFlags) {
Expand All @@ -55,7 +56,7 @@ export class DtoMapping {
case AddressRestrictionFlag.BlockOutgoingAddress:
return new AccountRestriction(
restrictionFlags,
prop.values.map((value) => Address.createFromEncoded(value as string)),
prop.values.map((value) => DtoMapping.toAddress(value as string)),
);
case MosaicRestrictionFlag.AllowMosaic:
case MosaicRestrictionFlag.BlockMosaic:
Expand All @@ -76,6 +77,22 @@ export class DtoMapping {
);
}

/**
* This method knows how to convert an address payload sent by Rest to Address.
*
* Currently rest sends hex encoded addresses, it is desired to use base32 encoded addresses.
*
* This method handles both format, encoded (deprecated) and base32 encoded addresses.
*
* Clients using this SDK will be able to process both payloads.
*
* @param value the address in encoded (6823BB7C3C089D996585466380EDBDC19D4959184893E38C) format or decoded/plain format (SB3KUBHATFCPV7UZQLWAQ2EUR6SIHBSBEOEDDDF3)
* @return the Address object.
*/
public static toAddress(value: string): Address {
return Convert.isHexString(value, 48) ? Address.createFromEncoded(value) : Address.createFromRawAddress(value);
Copy link
Member

@AnthonyLaw AnthonyLaw Oct 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example in transfer transaction, If the recipientAddress is alias THBIMC3THGH5RUYAAAAAAAAAAAAAAAAAAAAAAAA

It will throw an error Address Network unsupported right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven't removed private/mijin network support from the old SDKs yet. Unsure if it makes sense to remove them, this SDK would fade off eventually.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore my question.
Actually, I misunderstood, even though the alias namespace is still converted to a valid address format from REST.

}

/**
* Creates a copy of the first object adding the attributes of the second object.
* @param object the object to be cloned
Expand Down
49 changes: 32 additions & 17 deletions src/core/utils/UnresolvedMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { NamespaceId } from '../../model/namespace/NamespaceId';
import { NetworkType } from '../../model/network/NetworkType';
import { Convert } from '../format/Convert';
import { RawAddress } from '../format/RawAddress';
import { DtoMapping } from './DtoMapping';

/**
* @internal
Expand Down Expand Up @@ -48,26 +49,40 @@ export class UnresolvedMapping {
}

/**
* Map unresolved address string to Address or NamespaceId
* @param {string} address The unresolved address in hex
* Map unresolved address string to Address or NamespaceId.
*
* Input examples:
* - 6826D27E1D0A26CA4E316F901E23E55C8711DB20DF45C536 Hex address (old rest)
* - NATNE7Q5BITMUTRRN6IB4I7FLSDRDWZA35C4KNQ Base32 address (new reset)
* - 99C2860B73398FD8D3000000000000000000000000000000 Hex namespace id (old rest)
* - THBIMC3THGH5RUYAAAAAAAAAAAAAAAAAAAAAAAA Base32 namespace id (new rest)
*
* @param {string} unresolvedAddressString The unresolved address in hex (old rest) or base32 address (new rest)
* @returns {UnresolvedAddress}
*/
public static toUnresolvedAddress(address: string): UnresolvedAddress {
if (!Convert.isHexString(address)) {
throw new Error('Input string is not in valid hexadecimal notation.');
}
// If bit 0 of byte 0 is not set (like in 0x90), then it is a regular address.
// Else (e.g. 0x91) it represents a namespace id which starts at byte 1.
const bit0 = Convert.hexToUint8(address.substr(1, 2))[0];
if ((bit0 & 16) === 16) {
// namespaceId encoded hexadecimal notation provided
// only 8 bytes are relevant to resolve the NamespaceId
const relevantPart = address.substr(2, 16);
return NamespaceId.createFromEncoded(Convert.uint8ToHex(Convert.hexToUint8Reverse(relevantPart)));
}
public static toUnresolvedAddress(unresolvedAddressString: string): UnresolvedAddress {
const fromHexToUnresolvedAddress = (unresolvedAddressStringHex: string) => {
// If bit 0 of byte 0 is not set (like in 0x90), then it is a regular address.
// Else (e.g. 0x91) it represents a namespace id which starts at byte 1.
const bit0 = Convert.hexToUint8(unresolvedAddressStringHex.substr(1, 2))[0];
if ((bit0 & 16) === 16) {
// namespaceId encoded hexadecimal notation provided
// only 8 bytes are relevant to resolve the NamespaceId
const relevantPart = unresolvedAddressStringHex.substr(2, 16);
return NamespaceId.createFromEncoded(Convert.uint8ToHex(Convert.hexToUint8Reverse(relevantPart)));
}

// read address from encoded hexadecimal notation
return Address.createFromEncoded(address);
// read address from encoded hexadecimal notation
return Address.createFromEncoded(unresolvedAddressStringHex);
};

if (Convert.isHexString(unresolvedAddressString, 48)) {
// Old Rest
return fromHexToUnresolvedAddress(unresolvedAddressString);
} else {
// New rest
return fromHexToUnresolvedAddress(DtoMapping.toAddress(unresolvedAddressString).encoded());
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/infrastructure/AccountHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class AccountHttp extends Http implements AccountRepository {
return new AccountInfo(
dto.account.version || 1,
dto.id,
Address.createFromEncoded(dto.account.address),
DtoMapping.toAddress(dto.account.address),
UInt64.fromNumericString(dto.account.addressHeight),
dto.account.publicKey,
UInt64.fromNumericString(dto.account.publicKeyHeight),
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/BlockHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import { Observable } from 'rxjs';
import { BlockInfoDTO, BlockRoutesApi, ImportanceBlockDTO } from 'symbol-openapi-typescript-fetch-client';
import { DtoMapping } from '../core/utils/DtoMapping';
import { Address } from '../model/account/Address';
import { PublicAccount } from '../model/account/PublicAccount';
import { BlockInfo } from '../model/blockchain/BlockInfo';
import { BlockType } from '../model/blockchain/BlockType';
Expand Down Expand Up @@ -121,7 +120,7 @@ export class BlockHttp extends Http implements BlockRepository {
dto.block.proofGamma,
dto.block.proofScalar,
dto.block.proofVerificationHash,
Address.createFromEncoded(dto.block.beneficiaryAddress),
DtoMapping.toAddress(dto.block.beneficiaryAddress),
dto.meta.transactionsCount,
dto.meta.statementsCount,
);
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/HashLockHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import { Observable } from 'rxjs';
import { HashLockInfoDTO, HashLockRoutesApi } from 'symbol-openapi-typescript-fetch-client';
import { DtoMapping } from '../core/utils/DtoMapping';
import { Address } from '../model/account/Address';
import { MerkleStateInfo } from '../model/blockchain/MerkleStateInfo';
import { HashLockInfo } from '../model/lock/HashLockInfo';
import { MosaicId } from '../model/mosaic/MosaicId';
Expand Down Expand Up @@ -100,7 +99,7 @@ export class HashLockHttp extends Http implements HashLockRepository {
return new HashLockInfo(
dto.lock.version || 1,
dto.id,
Address.createFromEncoded(dto.lock.ownerAddress),
DtoMapping.toAddress(dto.lock.ownerAddress),
new MosaicId(dto.lock.mosaicId),
UInt64.fromNumericString(dto.lock.amount),
UInt64.fromNumericString(dto.lock.endHeight),
Expand Down
5 changes: 3 additions & 2 deletions src/infrastructure/Listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { catchError, distinctUntilChanged, filter, map, mergeMap, share, switchM
import { BlockInfoDTO } from 'symbol-openapi-typescript-fetch-client';
import * as WebSocket from 'ws';
import { parseObjectProperties } from '../core/format/Utilities';
import { MultisigChildrenTreeObject, MultisigGraphUtils } from '../core/utils';
import { DtoMapping, MultisigChildrenTreeObject, MultisigGraphUtils } from '../core/utils';
import { MultisigAccountInfo, UnresolvedAddress } from '../model';
import { Address } from '../model/account/Address';
import { PublicAccount } from '../model/account/PublicAccount';
Expand All @@ -36,6 +36,7 @@ import { MultisigHttp } from './MultisigHttp';
import { MultisigRepository } from './MultisigRepository';
import { NamespaceRepository } from './NamespaceRepository';
import { CreateTransactionFromDTO } from './transaction/CreateTransactionFromDTO';

export enum ListenerChannelName {
block = 'block',
confirmedAdded = 'confirmedAdded',
Expand Down Expand Up @@ -579,7 +580,7 @@ export class Listener implements IListener {
dto.block.proofGamma,
dto.block.proofScalar,
dto.block.proofVerificationHash,
dto.block.beneficiaryAddress ? Address.createFromEncoded(dto.block.beneficiaryAddress) : undefined,
dto.block.beneficiaryAddress ? DtoMapping.toAddress(dto.block.beneficiaryAddress) : undefined,
);
}

Expand Down
5 changes: 2 additions & 3 deletions src/infrastructure/MetadataHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { Observable } from 'rxjs';
import { MetadataInfoDTO, MetadataRoutesApi } from 'symbol-openapi-typescript-fetch-client';
import { Convert } from '../core/format/Convert';
import { DtoMapping } from '../core/utils/DtoMapping';
import { Address } from '../model/account/Address';
import { MerkleStateInfo } from '../model/blockchain';
import { Metadata } from '../model/metadata/Metadata';
import { MetadataEntry } from '../model/metadata/MetadataEntry';
Expand Down Expand Up @@ -122,8 +121,8 @@ export class MetadataHttp extends Http implements MetadataRepository {
new MetadataEntry(
metadataEntry.version || 1,
metadataEntry.compositeHash,
Address.createFromEncoded(metadataEntry.sourceAddress),
Address.createFromEncoded(metadataEntry.targetAddress),
DtoMapping.toAddress(metadataEntry.sourceAddress),
DtoMapping.toAddress(metadataEntry.targetAddress),
UInt64.fromHex(metadataEntry.scopedMetadataKey),
metadataEntry.metadataType.valueOf(),
Convert.decodeHex(metadataEntry.value),
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/MosaicHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { MosaicInfoDTO, MosaicRoutesApi } from 'symbol-openapi-typescript-fetch-client';
import { DtoMapping } from '../core/utils/DtoMapping';
import { Address } from '../model/account/Address';
import { MerkleStateInfo } from '../model/blockchain';
import { MosaicFlags } from '../model/mosaic/MosaicFlags';
import { MosaicId } from '../model/mosaic/MosaicId';
Expand Down Expand Up @@ -133,7 +132,7 @@ export class MosaicHttp extends Http implements MosaicRepository {
new MosaicId(mosaicInfo.mosaic.id),
UInt64.fromNumericString(mosaicInfo.mosaic.supply),
UInt64.fromNumericString(mosaicInfo.mosaic.startHeight),
Address.createFromEncoded(mosaicInfo.mosaic.ownerAddress),
DtoMapping.toAddress(mosaicInfo.mosaic.ownerAddress),
mosaicInfo.mosaic.revision,
new MosaicFlags(mosaicInfo.mosaic.flags),
mosaicInfo.mosaic.divisibility,
Expand Down
6 changes: 3 additions & 3 deletions src/infrastructure/MultisigHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ export class MultisigHttp extends Http implements MultisigRepository {
private toMultisigAccountInfo(dto: MultisigAccountInfoDTO): MultisigAccountInfo {
return new MultisigAccountInfo(
dto.multisig.version || 1,
Address.createFromEncoded(dto.multisig.accountAddress),
DtoMapping.toAddress(dto.multisig.accountAddress),
dto.multisig.minApproval,
dto.multisig.minRemoval,
dto.multisig.cosignatoryAddresses.map((cosigner) => Address.createFromEncoded(cosigner)),
dto.multisig.multisigAddresses.map((multisig) => Address.createFromEncoded(multisig)),
dto.multisig.cosignatoryAddresses.map((cosigner) => DtoMapping.toAddress(cosigner)),
dto.multisig.multisigAddresses.map((multisig) => DtoMapping.toAddress(multisig)),
);
}
}
6 changes: 3 additions & 3 deletions src/infrastructure/NamespaceHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class NamespaceHttp extends Http implements NamespaceRepository {
body.accountNames.map(
(accountName) =>
new AccountNames(
Address.createFromEncoded(accountName.address),
DtoMapping.toAddress(accountName.address),
accountName.names.map((name) => {
return new NamespaceName(new NamespaceId(name), name);
}),
Expand Down Expand Up @@ -255,7 +255,7 @@ export class NamespaceHttp extends Http implements NamespaceRepository {
dto.namespace.depth,
NamespaceHttp.extractLevels(dto.namespace),
NamespaceId.createFromEncoded(dto.namespace.parentId),
Address.createFromEncoded(dto.namespace.ownerAddress),
DtoMapping.toAddress(dto.namespace.ownerAddress),
UInt64.fromNumericString(dto.namespace.startHeight),
UInt64.fromNumericString(dto.namespace.endHeight),
NamespaceHttp.extractAlias(dto.namespace),
Expand Down Expand Up @@ -292,7 +292,7 @@ export class NamespaceHttp extends Http implements NamespaceRepository {
if (namespace.alias && namespace.alias.type.valueOf() === AliasType.Mosaic) {
return new MosaicAlias(new MosaicId(namespace.alias.mosaicId!));
} else if (namespace.alias && namespace.alias.type.valueOf() === AliasType.Address) {
return new AddressAlias(Address.createFromEncoded(namespace.alias.address!));
return new AddressAlias(DtoMapping.toAddress(namespace.alias.address!));
}
return new EmptyAlias();
}
Expand Down
3 changes: 1 addition & 2 deletions src/infrastructure/RestrictionMosaicHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
} from 'symbol-openapi-typescript-fetch-client';
import { DtoMapping } from '../core/utils';
import { MerkleStateInfo, UInt64 } from '../model';
import { Address } from '../model/account';
import { MosaicId } from '../model/mosaic';
import {
MosaicAddressRestriction,
Expand Down Expand Up @@ -100,7 +99,7 @@ export class RestrictionMosaicHttp extends Http implements RestrictionMosaicRepo
dto.mosaicRestrictionEntry.compositeHash,
dto.mosaicRestrictionEntry.entryType.valueOf(),
new MosaicId(dto.mosaicRestrictionEntry.mosaicId),
Address.createFromEncoded(addressRestrictionDto.mosaicRestrictionEntry.targetAddress),
DtoMapping.toAddress(addressRestrictionDto.mosaicRestrictionEntry.targetAddress),
addressRestrictionDto.mosaicRestrictionEntry.restrictions.map(RestrictionMosaicHttp.toMosaicAddressRestrictionItem),
);
}
Expand Down
5 changes: 2 additions & 3 deletions src/infrastructure/SecretLockHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { Observable } from 'rxjs';
import { SecretLockInfoDTO, SecretLockRoutesApi } from 'symbol-openapi-typescript-fetch-client';
import { DtoMapping } from '../core/utils';
import { UInt64 } from '../model';
import { Address } from '../model/account';
import { MerkleStateInfo } from '../model/blockchain';
import { SecretLockInfo } from '../model/lock';
import { MosaicId } from '../model/mosaic';
Expand Down Expand Up @@ -92,14 +91,14 @@ export class SecretLockHttp extends Http implements SecretLockRepository {
return new SecretLockInfo(
dto.lock.version || 1,
dto.id,
Address.createFromEncoded(dto.lock.ownerAddress),
DtoMapping.toAddress(dto.lock.ownerAddress),
new MosaicId(dto.lock.mosaicId),
UInt64.fromNumericString(dto.lock.amount),
UInt64.fromNumericString(dto.lock.endHeight),
dto.lock.status.valueOf(),
dto.lock.hashAlgorithm.valueOf(),
dto.lock.secret,
Address.createFromEncoded(dto.lock.recipientAddress),
DtoMapping.toAddress(dto.lock.recipientAddress),
dto.lock.compositeHash,
);
}
Expand Down
9 changes: 5 additions & 4 deletions src/infrastructure/receipt/CreateReceiptFromDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { ResolutionStatementInfoDTO, TransactionStatementInfoDTO } from 'symbol-openapi-typescript-fetch-client';
import { DtoMapping } from '../../core/utils';
import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping';
import { Address } from '../../model/account/Address';
import { UnresolvedAddress } from '../../model/account/UnresolvedAddress';
Expand Down Expand Up @@ -85,7 +86,7 @@ export const createAddressResolutionStatement = (statementInfoDTO: ResolutionSta
extractUnresolvedAddress(statementDTO.unresolved),
statementDTO.resolutionEntries.map((entry) => {
return new ResolutionEntry(
Address.createFromEncoded(entry.resolved),
DtoMapping.toAddress(entry.resolved),
new ReceiptSource(entry.source.primaryId, entry.source.secondaryId),
);
}),
Expand All @@ -100,7 +101,7 @@ export const createAddressResolutionStatement = (statementInfoDTO: ResolutionSta
*/
const createBalanceChangeReceipt = (receiptDTO): Receipt => {
return new BalanceChangeReceipt(
Address.createFromEncoded(receiptDTO.targetAddress),
DtoMapping.toAddress(receiptDTO.targetAddress),
new MosaicId(receiptDTO.mosaicId),
UInt64.fromNumericString(receiptDTO.amount),
receiptDTO.version,
Expand All @@ -116,8 +117,8 @@ const createBalanceChangeReceipt = (receiptDTO): Receipt => {
*/
const createBalanceTransferReceipt = (receiptDTO): Receipt => {
return new BalanceTransferReceipt(
Address.createFromEncoded(receiptDTO.senderAddress),
Address.createFromEncoded(receiptDTO.recipientAddress),
DtoMapping.toAddress(receiptDTO.senderAddress),
DtoMapping.toAddress(receiptDTO.recipientAddress),
new MosaicId(receiptDTO.mosaicId),
UInt64.fromNumericString(receiptDTO.amount),
receiptDTO.version,
Expand Down
3 changes: 2 additions & 1 deletion src/model/transaction/AddressAliasTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
TransactionBuilder,
} from 'catbuffer-typescript';
import { Convert } from '../../core/format';
import { DtoMapping } from '../../core/utils';
import { Address } from '../account/Address';
import { PublicAccount } from '../account/PublicAccount';
import { AliasAction } from '../namespace/AliasAction';
Expand Down Expand Up @@ -131,7 +132,7 @@ export class AddressAliasTransaction extends Transaction {
: Deadline.createFromDTO((builder as AddressAliasTransactionBuilder).getDeadline().timestamp),
builder.getAliasAction().valueOf(),
new NamespaceId(builder.getNamespaceId().namespaceId),
Address.createFromEncoded(Convert.uint8ToHex(builder.getAddress().address)),
DtoMapping.toAddress(Convert.uint8ToHex(builder.getAddress().address)),
networkType,
isEmbedded ? new UInt64([0, 0]) : new UInt64((builder as AddressAliasTransactionBuilder).fee.amount),
signature,
Expand Down
Loading