UNPKG

@libra-opensource/client-sdk-typescript

Version:
170 lines (169 loc) 9.88 kB
"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();