@libra-opensource/client-sdk-typescript
Version:
170 lines (169 loc) • 9.88 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const bech32_1 = __importDefault(require("bech32"));
const signer_1 = require("./utils/signer");
const accountKeys_1 = __importDefault(require("./account/accountKeys"));
const constants_1 = require("./constants");
const bytes_1 = require("./utils/bytes");
const diemTypes_1 = require("./bcs/diemTypes");
const bcsSerializer_1 = require("./bcs/bcs/bcsSerializer");
const diemStdlib_1 = require("./bcs/diemStdlib");
const intent_1 = __importDefault(require("./utils/intent"));
const sha3_1 = require("sha3");
const util_1 = __importDefault(require("util"));
class DiemUtils {
static generateAccountKeys(seed) {
const keyPair = signer_1.Signer.generateKeyPair(seed);
return new accountKeys_1.default(keyPair);
}
static createAddCurrencyToAccountTransaction(sender, sequenceNumber, currency, gasCurrency, gasUnitPrice, maxGasAmount, expirationTimestampSecs, network) {
const currencyTag = DiemUtils.makeCurrencyTypeTag(currency);
const script = diemStdlib_1.Stdlib.encodeAddCurrencyToAccountScript(currencyTag);
return new diemTypes_1.RawTransaction(DiemUtils.makeAccountAddress(sender), sequenceNumber, new diemTypes_1.TransactionPayloadVariantScript(script), maxGasAmount, gasUnitPrice, gasCurrency, expirationTimestampSecs, new diemTypes_1.ChainId(network));
}
static createGeneralMetadata(receiverSubaddress, senderSubaddress, referenceEventNumber) {
const serializer = new bcsSerializer_1.BcsSerializer();
const metadata = new diemTypes_1.MetadataVariantGeneralMetadata(new diemTypes_1.GeneralMetadataVariantGeneralMetadataVersion0(new diemTypes_1.GeneralMetadataV0(receiverSubaddress ? bytes_1.bytesToBuffer(receiverSubaddress) : null, senderSubaddress ? bytes_1.bytesToBuffer(senderSubaddress) : null, referenceEventNumber !== null && referenceEventNumber !== void 0 ? referenceEventNumber : null)));
metadata.serialize(serializer);
const signature = new Uint8Array();
return [serializer.getBytes(), signature];
}
static signTravelRuleMetadata(metadata, sender, amount, privateKey) {
const sigSerializer = new bcsSerializer_1.BcsSerializer();
const address = DiemUtils.makeAccountAddress(sender);
address.serialize(sigSerializer);
sigSerializer.serializeU64(amount);
const dualAttestationMessage = bytes_1.concat(metadata, bytes_1.concat(sigSerializer.getBytes(), this.textEncoder.encode('@@$$DIEM_ATTEST$$@@')));
return signer_1.Signer.sign(privateKey, dualAttestationMessage);
}
static createTravelRuleMetadata(offChainReferenceId) {
const serializer = new bcsSerializer_1.BcsSerializer();
const metadata = new diemTypes_1.MetadataVariantTravelRuleMetadata(new diemTypes_1.TravelRuleMetadataVariantTravelRuleMetadataVersion0(new diemTypes_1.TravelRuleMetadataV0(offChainReferenceId !== null && offChainReferenceId !== void 0 ? offChainReferenceId : null)));
metadata.serialize(serializer);
return serializer.getBytes();
}
static createP2PTransaction(sender, sequenceNumber, currency, receiver, amount, gasCurrency, gasUnitPrice, maxGasAmount, expirationTimestampSecs, network, metadata, metadataSignature) {
const currencyTag = DiemUtils.makeCurrencyTypeTag(currency);
const script = diemStdlib_1.Stdlib.encodePeerToPeerWithMetadataScript(currencyTag, DiemUtils.makeAccountAddress(receiver), amount, metadata, metadataSignature);
return new diemTypes_1.RawTransaction(DiemUtils.makeAccountAddress(sender), sequenceNumber, new diemTypes_1.TransactionPayloadVariantScript(script), maxGasAmount, gasUnitPrice, gasCurrency, expirationTimestampSecs, new diemTypes_1.ChainId(network));
}
static signTransaction(rawTransaction, accountKeys) {
const txSerializer = new bcsSerializer_1.BcsSerializer();
rawTransaction.serialize(txSerializer);
const signature = signer_1.Signer.signRawTransaction(bytes_1.bytesToBuffer(accountKeys.privateKey), txSerializer.getBytes());
return new diemTypes_1.SignedTransaction(rawTransaction, new diemTypes_1.TransactionAuthenticatorVariantEd25519(new diemTypes_1.Ed25519PublicKey(bytes_1.bytesToBuffer(accountKeys.publicKey)), new diemTypes_1.Ed25519Signature(signature)));
}
static hashTransaction(signedTxBytes) {
const prefixHash = new sha3_1.SHA3(256);
prefixHash.update('DIEM::Transaction');
const prefix = prefixHash.digest();
const transactionHash = new sha3_1.SHA3(256);
transactionHash.update(prefix);
transactionHash.update(Buffer.from([0]));
transactionHash.update(Buffer.from(signedTxBytes));
return transactionHash.digest().toString('hex');
}
static encodeAddress(address, subAddress, hrp = 'tdm') {
const addressBytes = bytes_1.bytesToBuffer(address);
if (!subAddress ||
(subAddress.length != constants_1.subAddressBytesSize &&
/^0+$/.test(subAddress.toString()))) {
subAddress = constants_1.zeroSubAddress;
}
const subAddressBytes = bytes_1.bytesToBuffer(subAddress);
if (addressBytes.length != constants_1.addressBytesSize) {
throw new TypeError(`Address size should be ${constants_1.addressBytesSize} bytes, got: ${addressBytes.length}`);
}
if (subAddressBytes.length != constants_1.subAddressBytesSize) {
throw new TypeError(`Subaddress size should be ${constants_1.subAddressBytesSize} bytes, got: ${subAddressBytes.length}`);
}
const mergedAddressBytes = bytes_1.concat(addressBytes, subAddressBytes);
const words = bech32_1.default.toWords(mergedAddressBytes);
words.unshift(constants_1.bech32AddressVersion);
return bech32_1.default.encode(hrp, words);
}
static decodeAddress(hrp, bech32Address) {
if (!constants_1.bech32AddressLength.includes(bech32Address.length)) {
throw new TypeError(`Bech32 address size should be ${constants_1.bech32AddressLength}, got: ${bech32Address.length}`);
}
const { prefix, words } = bech32_1.default.decode(bech32Address);
if (prefix !== hrp) {
throw new TypeError(`Wrong Diem address Bech32 human readable part (prefix): requested ${hrp}, got ${prefix}`);
}
const addressVersion = words[0];
const mergedAddress = new Uint8Array(bech32_1.default.fromWords(words.slice(1)));
if (constants_1.bech32AddressVersion !== addressVersion) {
throw new TypeError(`Version mismatch. Expected ${constants_1.bech32AddressVersion}, got ${addressVersion}`);
}
const address = bytes_1.bytesToHexString(mergedAddress.slice(0, constants_1.addressBytesSize));
const subAddress = bytes_1.bytesToHexString(mergedAddress.slice(constants_1.addressBytesSize));
return [address, subAddress.length ? subAddress : undefined];
}
static encodeIntent(intent) {
const bech32Address = DiemUtils.encodeAddress(intent.address, intent.subAddress, intent.hrp);
const url = new URL(`${constants_1.diemScheme}://${bech32Address}`);
if (intent.currency) {
url.searchParams.set('c', intent.currency);
}
if (intent.amount) {
url.searchParams.set('am', intent.amount.toString());
}
return url;
}
static decodeIntent(hrp, intent) {
const protocol = intent.protocol.slice(0, -1);
if (protocol !== constants_1.diemScheme) {
throw new TypeError(`invalid intent scheme: ${protocol}`);
}
const [address, subAddress] = DiemUtils.decodeAddress(hrp, intent.hostname);
let currency;
if (intent.searchParams.has('c')) {
currency = intent.searchParams.get('c');
}
let amount;
if (intent.searchParams.has('am')) {
amount = parseInt(intent.searchParams.get('am'));
}
return new intent_1.default(hrp, address, subAddress, currency, amount);
}
static makeCurrencyTypeTag(currency) {
const structTag = new diemTypes_1.StructTag(DiemUtils.makeAccountAddress(constants_1.coreCodeAddressHex), new diemTypes_1.Identifier(currency), new diemTypes_1.Identifier(currency), []);
return new diemTypes_1.TypeTagVariantStruct(structTag);
}
static makeAccountAddress(address) {
const asTuple = [];
bytes_1.bytesToBuffer(address).forEach((value) => asTuple.push([value]));
return new diemTypes_1.AccountAddress(asTuple);
}
static parseAccountAddress(address) {
const addressBuffer = new Uint8Array(address.value.length);
let index = 0;
for (const value of address.value) {
const [octet] = value;
addressBuffer[index] = octet;
++index;
}
return addressBuffer;
}
static matchScriptByCode(code) {
const codeHex = bytes_1.bytesToHexString(code);
const scripts = Object.entries(diemStdlib_1.Stdlib.ScriptArgs).filter(([, scriptDef]) => {
const name = `${scriptDef.codeName}_CODE`;
const stdCode = bytes_1.bytesToHexString(diemStdlib_1.Stdlib[name]);
return stdCode === codeHex;
});
if (scripts.length < 1) {
return undefined;
}
if (scripts.length > 1) {
throw new Error(`More than one script matches ${codeHex}`);
}
const [, def] = scripts[0];
return def;
}
}
exports.default = DiemUtils;
DiemUtils.textEncoder = typeof window === 'undefined' ? new util_1.default.TextEncoder() : new TextEncoder();