@fruitsjs/core
Version:
Principal package with functions and models for building Fruits Eco-Blockchain applications.
161 lines (139 loc) • 5.98 kB
text/typescript
import { getAccountIdFromPublicKey } from '@fruitsjs/crypto';
import {
convertBase36StringToHexString,
convertHexStringToBase36String,
} from '@fruitsjs/util';
import { ensureReedSolomonAddress } from './ensureReedSolomonAddress';
import { tokenizeReedSolomonAddress } from './tokenizeReedSolomonAddress';
import { convertReedSolomonAddressToNumericId } from './convertReedSolomonAddressToNumericId';
import { convertNumericIdToReedSolomonAddress } from './convertNumericIdToReedSolomonAddress';
import { AddressPrefix } from '../constants';
function ensureValidPublicKey(publicKey: string): void {
if (!(publicKey && /^[a-fA-F0-9]{64}/.test(publicKey))) {
throw new Error('Invalid Public Key Format');
}
}
/**
* A Value Object to facilitate Address conversions.
*
* @module core
*/
export class Address {
private _publicKey: string;
private _numericId: string;
private _rs: string;
private constructor(args: { publicKey?: string, prefix?: string, address?: string }) {
if (args.publicKey) {
this.constructFromPublicKey(args.publicKey, args.prefix);
} else if (args.address) {
this.constructFromAddress(args.address);
} else {
throw new Error('Invalid arguments');
}
}
/**
* Tries to create the address from whatever input is given
* @param anyValidAddress Any valid address, may it be Reed Solomon address, numeric ID, or public key
* @param prefix An optional prefix, which can be used to substitute the default [[AddressPrefix.MainNet]]
* @return The new address, if the input was valid
* @throws when no valid format
*/
public static create(anyValidAddress: string, prefix: string = AddressPrefix.MainNet): Address {
try {
tokenizeReedSolomonAddress(anyValidAddress);
return Address.fromReedSolomonAddress(anyValidAddress);
} catch (e) {
try {
ensureValidPublicKey(anyValidAddress);
return Address.fromPublicKey(anyValidAddress, prefix);
} catch (innerError) {
return Address.fromNumericId(anyValidAddress, prefix);
}
}
}
public static fromNumericId(numericId: string, prefix: string = AddressPrefix.MainNet): Address {
const address = convertNumericIdToReedSolomonAddress(numericId, prefix);
return new Address({ address });
}
/**
* Creates an Account Address object from public key
* @param publicKey The public key of that address (in hex format)
* @param prefix The Reed-Solomon Address prefix
*/
public static fromPublicKey(publicKey: string, prefix: string = AddressPrefix.MainNet): Address {
return new Address({ publicKey: publicKey.toUpperCase(), prefix });
}
/**
* Creates an Account Address object from extended Reed-Solomon address
* @param address The Reed-Solomon address in simple or extended format (with base36 suffix)
* @throws Error if the passed address is invalid
*/
public static fromReedSolomonAddress(address: string): Address {
ensureReedSolomonAddress(address);
const { extension, prefix } = tokenizeReedSolomonAddress(address);
if (extension) {
const publicKey = convertBase36StringToHexString(extension);
if (convertReedSolomonAddressToNumericId(address) !== getAccountIdFromPublicKey(publicKey)) {
throw Error('Address and Public Key do not match');
}
return new Address({ publicKey, prefix });
}
return new Address({ address });
}
/**
* @return Gets public key
*/
getPublicKey(): string {
return this._publicKey;
}
/**
* @return Gets numeric Account Id
*/
getNumericId(): string {
return this._numericId;
}
/**
* Gets as Reed Solomon representation
* @param withPrefix If false, the address without prefix will be returned. Default: true
* @return Reed Solomon Address Format
* @see [[Address.getReedSolomonAddressExtended]]
*/
getReedSolomonAddress(withPrefix = true): string {
return withPrefix ? this._rs : this._rs.substr(this._rs.indexOf('-') + 1);
}
/**
* Gets as extended Reed Solomon representation carrying the public key as suffix in base36 encoding
*
* This method requires that the address was created from a public key or extended address.
*
* @param withPrefix If false, the address without prefix will be returned. Default: true
* @return Extended Reed Solomon Address Format
* @throws if no public key is available
* @see [[Address.getReedSolomonAddress]]
*/
getReedSolomonAddressExtended(withPrefix = true): string {
if (!this._publicKey) {
throw new Error('No public key available');
}
return `${this.getReedSolomonAddress(withPrefix)}-${convertHexStringToBase36String(this._publicKey)}`.toUpperCase();
}
/**
* Checks for equality
* @param address The other address to be compared
* @return true if equal, otherwise false
*/
public equals(address: Address): boolean {
return this._numericId === address._numericId;
}
private constructFromPublicKey(publicKey: string, prefix: string): void {
ensureValidPublicKey(publicKey);
this._publicKey = publicKey;
this._numericId = getAccountIdFromPublicKey(publicKey);
this._rs = convertNumericIdToReedSolomonAddress(this._numericId, prefix);
}
private constructFromAddress(address: string): void {
this._publicKey = '';
this._rs = address;
this._numericId = convertReedSolomonAddressToNumericId(address);
}
}