@radixdlt/account
Version:
A JavaScript client library for interacting with the Radix Distributed Ledger.
191 lines • 9.47 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResourceIdentifier = exports.isResourceIdentifierOrUnsafeInput = exports.isResourceIdentifierUnsafeInput = exports.isResourceIdentifier = void 0;
const neverthrow_1 = require("neverthrow");
const util_1 = require("@radixdlt/util");
const crypto_1 = require("@radixdlt/crypto");
const primitives_1 = require("@radixdlt/primitives");
const bech32_1 = require("../bech32");
const encoding = bech32_1.Encoding.BECH32;
const maxLength = undefined; // arbitrarily chosen
const versionByteNativeToken = 0x01;
const versionByteNonNativeToken = 0x03;
const hrpSuffixFromNetwork = (network) => primitives_1.HRP[network].RRI_suffix;
const networkFromHRPSuffix = (hrp) => hrp === primitives_1.HRP.mainnet.RRI_suffix
? (0, neverthrow_1.ok)(primitives_1.Network.MAINNET)
: hrp === primitives_1.HRP.stokenet.RRI_suffix
? (0, neverthrow_1.ok)(primitives_1.Network.STOKENET)
: hrp === primitives_1.HRP.localnet.RRI_suffix
? (0, neverthrow_1.ok)(primitives_1.Network.LOCALNET)
: hrp === primitives_1.HRP.releasenet.RRI_suffix
? (0, neverthrow_1.ok)(primitives_1.Network.RELEASENET)
: hrp === primitives_1.HRP.rcnet.RRI_suffix
? (0, neverthrow_1.ok)(primitives_1.Network.RCNET)
: hrp === primitives_1.HRP.milestonenet.RRI_suffix
? (0, neverthrow_1.ok)(primitives_1.Network.MILESTONENET)
: hrp === primitives_1.HRP.testnet6.RRI_suffix
? (0, neverthrow_1.ok)(primitives_1.Network.TESTNET6)
: hrp === primitives_1.HRP.sandpitnet.RRI_suffix
? (0, neverthrow_1.ok)(primitives_1.Network.SANDPITNET)
: (0, neverthrow_1.err)(new Error(`Failed to parse network from HRP ${hrp} for ValidatorAddress.`));
const __create = (input) => (Object.assign(Object.assign({}, input), { __witness: 'isRRI', equals: (other) => {
if (!(0, exports.isResourceIdentifier)(other))
return false;
const same = other.name === input.name &&
(0, util_1.buffersEquals)(other.hash, input.hash) &&
input.network === other.network;
if (same) {
if (other.toString() !== input.toString()) {
const errMsg = `ResourceIdentifiers believed to be equal, but return different values when calling toString, (this)'${input.toString()}' vs other: '${other.toString()}'`;
console.error(errMsg);
throw new Error(errMsg);
}
}
return same;
} }));
const fromBech32String = (bechString) => {
// const hrpSuffix = hrpBetanetSuffix // TODO make dependent on Network!
const decodingResult = bech32_1.Bech32.decode({ bechString, encoding, maxLength });
if (!decodingResult.isOk()) {
const errMsg = `Failed to Bech32 decode RRI, underlying error: ${(0, util_1.msgFromError)(decodingResult.error)}`;
return (0, neverthrow_1.err)(new Error(errMsg));
}
const decoded = decodingResult.value;
const hrp = decoded.hrp;
if (!Object.keys(primitives_1.HRP).some(network => hrp.endsWith(primitives_1.HRP[network].RRI_suffix))) {
const errMsg = `suffix found for hrp "${hrp}" not supported.`;
return (0, neverthrow_1.err)(new Error(errMsg));
}
const nameToValidate = hrp.split('_')[0];
const hrpSuffix = '_' + hrp.split('_')[1];
const networkResult = networkFromHRPSuffix(hrpSuffix);
if (!networkResult.isOk()) {
const errMsg = `Expected to get network from HRP suffix '${hrpSuffix}', but failed to get it.`;
return (0, neverthrow_1.err)(new Error(errMsg));
}
const network = networkResult.value;
const nameValidationResult = validateCharsInName(nameToValidate);
if (!nameValidationResult.isOk()) {
return (0, neverthrow_1.err)(nameValidationResult.error);
}
const name = nameValidationResult.value;
const processed = decoded.data;
const combinedDataResult = bech32_1.Bech32.convertDataFromBech32(processed);
if (!combinedDataResult.isOk()) {
const errMsg = `Failed to convertDataFromBech32 data, underlying error: ${(0, util_1.msgFromError)(combinedDataResult.error)}`;
console.error(errMsg);
return (0, neverthrow_1.err)(new Error(errMsg));
}
const combinedData = combinedDataResult.value;
if (combinedData.length === 0) {
const errMsg = `The data part of RRI should NEVER be empty, must at least contain 1 version byte ('${versionByteNativeToken}' for native token, or '${versionByteNonNativeToken}' for other tokens)`;
console.error(errMsg);
return (0, neverthrow_1.err)(new Error(errMsg));
}
const versionByte = combinedData[0];
if (!(versionByte === versionByteNativeToken ||
versionByte === versionByteNonNativeToken)) {
const errMsg = `The version byte must be either: '${versionByteNativeToken}' for native token, or '${versionByteNonNativeToken}' for other tokens, but got: ${versionByte}, bechString: '${bechString}'`;
console.error(errMsg);
return (0, neverthrow_1.err)(new Error(errMsg));
}
const isNativeToken = versionByte === versionByteNativeToken;
if (isNativeToken) {
if (combinedData.length > 1) {
const errMsg = `Expected data to be empty for native token, but got: #${combinedData.length - 1 // minus 1 because we substract the 'versionByte'
} bytes`;
console.error(errMsg);
return (0, neverthrow_1.err)(new Error(errMsg));
}
}
else {
if (combinedData.length <= 1) {
const errMsg = `Expected data to be non empty for non native token`;
console.error(errMsg);
return (0, neverthrow_1.err)(new Error(errMsg));
}
}
return (0, neverthrow_1.ok)(__create({
hash: combinedData,
network,
name,
toString: () => bechString,
}));
};
const validateCharsInName = (name) => {
const regexLowerAlphaNumerics = new RegExp('^[a-z0-9]+$');
if (!regexLowerAlphaNumerics.test(name)) {
const errMsg = `Illegal characters found in name`;
// console.error(errMsg)
return (0, neverthrow_1.err)(new Error(errMsg));
}
return (0, neverthrow_1.ok)(name);
};
const withNameRawDataAndVersionByte = (input) => {
const { versionByte, hash, network } = input;
const hrpSuffix = hrpSuffixFromNetwork(network);
return validateCharsInName(input.name).andThen(name => {
const hrp = `${name}${hrpSuffix}`;
const combinedData = Buffer.concat([Buffer.from([versionByte]), hash]);
return bech32_1.Bech32.convertDataToBech32(combinedData)
.andThen(processed => bech32_1.Bech32.encode({
data: processed,
hrp,
encoding,
maxLength,
}))
.map(bech32 => __create({
hash,
network,
name,
toString: () => bech32.toString(),
}));
});
};
const systemRRIForNetwork = (input) => withNameRawDataAndVersionByte(Object.assign(Object.assign({}, input), { versionByte: versionByteNativeToken, hash: Buffer.alloc(0) }));
const hashByteCount = 26;
const pkToHash = (input) => {
const { name, publicKey } = input;
const nameBytes = Buffer.from(name, 'utf8');
const pubKeyBytes = publicKey.asData({ compressed: true });
const dataToHash = Buffer.concat([pubKeyBytes, nameBytes]);
const hash = (0, crypto_1.sha256Twice)(dataToHash);
return hash.slice(-hashByteCount); // last bytes
};
const fromPublicKeyAndNameAndNetwork = (input) => withNameRawDataAndVersionByte(Object.assign(Object.assign({}, input), { versionByte: versionByteNonNativeToken, hash: pkToHash(input) }));
const fromBuffer = (buffer) => {
if (buffer.length === 1 && buffer[0] === 0x01) {
return systemRRIForNetwork({
name: 'xrd',
network: primitives_1.Network.MAINNET, // Yikes!
});
}
return (0, neverthrow_1.err)(new Error('Failed to create non XRD RRI because we do not have access to the HRP.'));
};
const isResourceIdentifier = (something) => {
const inspection = something;
return (
// inspection.hash !== undefined &&
inspection.__witness !== undefined &&
inspection.__witness === 'isRRI' &&
inspection.name !== undefined &&
inspection.toString !== undefined &&
inspection.equals !== undefined);
};
exports.isResourceIdentifier = isResourceIdentifier;
const isResourceIdentifierUnsafeInput = (something) => typeof something === 'string' || Buffer.isBuffer(something);
exports.isResourceIdentifierUnsafeInput = isResourceIdentifierUnsafeInput;
const isResourceIdentifierOrUnsafeInput = (something) => (0, exports.isResourceIdentifier)(something) ||
(0, exports.isResourceIdentifierUnsafeInput)(something);
exports.isResourceIdentifierOrUnsafeInput = isResourceIdentifierOrUnsafeInput;
const fromUnsafe = (input) => (0, exports.isResourceIdentifier)(input)
? (0, neverthrow_1.ok)(input)
: typeof input === 'string'
? fromBech32String(input)
: fromBuffer(input);
exports.ResourceIdentifier = {
systemRRIForNetwork,
fromPublicKeyAndNameAndNetwork,
fromUnsafe,
};
//# sourceMappingURL=resourceIdentifier.js.map