@hdwallet/core
Version:
A complete Hierarchical Deterministic (HD) Wallet generator for 200+ cryptocurrencies, built with TypeScript.
126 lines • 6.79 kB
JavaScript
"use strict";
// SPDX-License-Identifier: MIT
Object.defineProperty(exports, "__esModule", { value: true });
exports.MoneroAddress = void 0;
const cryptocurrencies_1 = require("../cryptocurrencies");
const base58_1 = require("../libs/base58");
const crypto_1 = require("../crypto");
const eccs_1 = require("../eccs");
const utils_1 = require("../utils");
const cryptocurrency_1 = require("../cryptocurrencies/cryptocurrency");
const exceptions_1 = require("../exceptions");
const address_1 = require("./address");
class MoneroAddress extends address_1.Address {
static checksumLength = cryptocurrencies_1.Monero.PARAMS.CHECKSUM_LENGTH;
static paymentIDLength = cryptocurrencies_1.Monero.PARAMS.PAYMENT_ID_LENGTH;
static network = cryptocurrencies_1.Monero.DEFAULT_NETWORK;
static addressType = cryptocurrencies_1.Monero.DEFAULT_ADDRESS_TYPE;
static networks = {
mainnet: {
addressTypes: {
'standard': cryptocurrencies_1.Monero.NETWORKS.MAINNET.STANDARD,
'integrated': cryptocurrencies_1.Monero.NETWORKS.MAINNET.INTEGRATED,
'sub-address': cryptocurrencies_1.Monero.NETWORKS.MAINNET.SUB_ADDRESS
}
},
stagenet: {
addressTypes: {
'standard': cryptocurrencies_1.Monero.NETWORKS.STAGENET.STANDARD,
'integrated': cryptocurrencies_1.Monero.NETWORKS.STAGENET.INTEGRATED,
'sub-address': cryptocurrencies_1.Monero.NETWORKS.STAGENET.SUB_ADDRESS
}
},
testnet: {
addressTypes: {
'standard': cryptocurrencies_1.Monero.NETWORKS.TESTNET.STANDARD,
'integrated': cryptocurrencies_1.Monero.NETWORKS.TESTNET.INTEGRATED,
'sub-address': cryptocurrencies_1.Monero.NETWORKS.TESTNET.SUB_ADDRESS
}
}
};
static getName() {
return 'Monero';
}
static computeChecksum(data) {
return (0, crypto_1.keccak256)(data).subarray(0, this.checksumLength);
}
static encode(publicKeys, options = {
network: this.network, addressType: this.addressType
}) {
const { spendPublicKey, viewPublicKey } = publicKeys;
const addressType = options.addressType ?? this.addressType;
const paymentID = options.paymentID ? (0, utils_1.getBytes)(options.paymentID) : undefined;
const spend = (0, eccs_1.validateAndGetPublicKey)(spendPublicKey, eccs_1.SLIP10Ed25519MoneroPublicKey);
const view = (0, eccs_1.validateAndGetPublicKey)(viewPublicKey, eccs_1.SLIP10Ed25519MoneroPublicKey);
if (paymentID && paymentID.length !== this.paymentIDLength) {
throw new exceptions_1.BaseError('Invalid payment ID length', {
expected: this.paymentIDLength, got: paymentID.length
});
}
const network = options.network ?? this.network;
const resolvedNetwork = (0, utils_1.ensureTypeMatch)(network, cryptocurrency_1.Network, { otherTypes: ['string'] });
const networkName = resolvedNetwork.isValid ? resolvedNetwork.value.NAME : network;
const version = (0, utils_1.integerToBytes)(this.networks[networkName].addressTypes[addressType]);
const payload = (0, utils_1.concatBytes)(version, spend.getRawCompressed(), view.getRawCompressed(), (0, utils_1.getBytes)(paymentID ?? new Uint8Array(0)));
const checksum = this.computeChecksum((0, utils_1.getBytes)(payload));
return (0, base58_1.encodeMonero)((0, utils_1.getBytes)((0, utils_1.concatBytes)(payload, checksum)));
}
static decode(address, options = {
network: this.network, addressType: this.addressType
}) {
const addressType = options.addressType ?? this.addressType;
const paymentID = (0, utils_1.getBytes)(options.paymentID ?? new Uint8Array(0));
const decoded = (0, base58_1.decodeMonero)(address);
const checksum = decoded.subarray(-this.checksumLength);
const payloadWithPrefix = decoded.subarray(0, -this.checksumLength);
const computedChecksum = this.computeChecksum(payloadWithPrefix);
if (!(0, utils_1.equalBytes)(checksum, computedChecksum)) {
throw new exceptions_1.AddressError('Invalid checksum', {
expected: (0, utils_1.bytesToString)(checksum), got: (0, utils_1.bytesToString)(computedChecksum)
});
}
const network = options.network ?? this.network;
const resolvedNetwork = (0, utils_1.ensureTypeMatch)(network, cryptocurrency_1.Network, { otherTypes: ['string'] });
const networkName = resolvedNetwork.isValid ? resolvedNetwork.value.NAME : network;
const version = (0, utils_1.integerToBytes)(this.networks[networkName].addressTypes[addressType]);
const versionGot = payloadWithPrefix.subarray(0, version.length);
if (!(0, utils_1.equalBytes)(versionGot, version)) {
throw new exceptions_1.AddressError('Invalid version', { expected: version, got: versionGot });
}
const payload = payloadWithPrefix.subarray(version.length);
const pubkeyLen = eccs_1.SLIP10Ed25519MoneroPublicKey.getCompressedLength();
let spend;
let view;
if (payload.length === 2 * pubkeyLen) {
spend = payload.subarray(0, pubkeyLen);
view = payload.subarray(pubkeyLen);
}
else if (payload.length === 2 * pubkeyLen + this.paymentIDLength) {
if (!paymentID || paymentID.length !== this.paymentIDLength) {
throw new exceptions_1.BaseError('Missing or invalid payment ID');
}
const paymentIDGot = payload.subarray(-this.paymentIDLength);
if (!(0, utils_1.equalBytes)(paymentID, paymentIDGot)) {
throw new exceptions_1.BaseError('Payment ID mismatch', {
expected: (0, utils_1.bytesToString)(paymentIDGot), got: (0, utils_1.bytesToString)(paymentID)
});
}
spend = payload.subarray(0, pubkeyLen);
view = payload.subarray(pubkeyLen, pubkeyLen * 2);
}
else {
throw new exceptions_1.AddressError('Invalid payload length', {
expected: 2 * pubkeyLen, got: payload.length
});
}
if (!eccs_1.SLIP10Ed25519MoneroPublicKey.isValidBytes(spend)) {
throw new exceptions_1.BaseError('Invalid spend public key');
}
if (!eccs_1.SLIP10Ed25519MoneroPublicKey.isValidBytes(view)) {
throw new exceptions_1.BaseError('Invalid view public key');
}
return [(0, utils_1.bytesToString)(spend), (0, utils_1.bytesToString)(view)];
}
}
exports.MoneroAddress = MoneroAddress;
//# sourceMappingURL=monero.js.map