UNPKG

@pgchain/blockchain-libs

Version:
270 lines 12.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Provider = exports.buildSignedTx = exports.buildUnsignedRawTx = void 0; const bytes_1 = require("@ethersproject/bytes"); const js_sdk_1 = __importDefault(require("@onekeyfe/js-sdk")); const starcoin_1 = require("@starcoin/starcoin"); const ethUtil = __importStar(require("ethereumjs-util")); const precondtion_1 = require("../../../basic/precondtion"); const abc_1 = require("../../abc"); const starcoin_2 = require("./starcoin"); class Provider extends abc_1.BaseProvider { get starcoin() { return this.clientSelector((i) => i instanceof starcoin_2.StcClient); } async buildUnsignedTx(unsignedTx) { var _a; const feePricePerUnit = unsignedTx.feePricePerUnit ? unsignedTx.feePricePerUnit : (await (await this.starcoin).getFeePricePerUnit()).normal.price; const txInput = unsignedTx.inputs[0]; const txOutput = unsignedTx.outputs[0]; const payload = unsignedTx.payload || {}; let nonce = unsignedTx.nonce; let feeLimit = unsignedTx.feeLimit; if (txInput && txOutput) { const senderPublicKey = txInput.publicKey; if (!feeLimit) { (0, precondtion_1.check)(senderPublicKey, 'senderPublicKey is required'); } const fromAddr = txInput.address; let toAddr = txOutput.address; const amount = txOutput.value; const tokenAddress = txOutput.tokenAddress; if (toAddr.startsWith('stc')) { const riv = starcoin_1.encoding.decodeReceiptIdentifier(toAddr); toAddr = riv.accountAddress.startsWith('0x') ? riv.accountAddress : '0x' + riv.accountAddress; } if (typeof nonce === 'undefined') { nonce = (_a = (await (await this.starcoin).getAddresses([fromAddr]))[0]) === null || _a === void 0 ? void 0 : _a.nonce; (0, precondtion_1.check)(typeof nonce !== 'undefined', 'nonce is not available'); } payload.expirationTime = payload.expirationTime || Math.floor(Date.now() / 1000) + 60 * 60; const strTypeArgs = [tokenAddress !== null && tokenAddress !== void 0 ? tokenAddress : '0x1::STC::STC']; const tyArgs = starcoin_1.utils.tx.encodeStructTypeTags(strTypeArgs); const functionId = '0x1::TransferScripts::peer_to_peer_v2'; const amountSCSHex = (function () { const se = new starcoin_1.bcs.BcsSerializer(); se.serializeU128(BigInt(amount.toNumber())); return (0, bytes_1.hexlify)(se.getBytes()); })(); const args = [(0, bytes_1.arrayify)(toAddr), (0, bytes_1.arrayify)(amountSCSHex)]; payload.scriptFn = starcoin_1.utils.tx.encodeScriptFunction(functionId, tyArgs, args); feeLimit = feeLimit || (await (await this.starcoin).estimateGasLimit({ chain_id: this.chainInfo.implOptions.chainId, gas_unit_price: feePricePerUnit.toNumber(), sender: fromAddr, sender_public_key: senderPublicKey, sequence_number: nonce, max_gas_amount: 1000000, script: { code: functionId, type_args: strTypeArgs, args: [toAddr, '19950u128'], }, })); } return { inputs: txInput ? [txInput] : [], outputs: txOutput ? [txOutput] : [], feeLimit, feePricePerUnit, nonce, payload, }; } async pubkeyToAddress(verifier, encoding = 'hex') { let address = ''; const pubkeyBytes = await verifier.getPubkey(); if (encoding === 'hex') { address = starcoin_1.encoding.publicKeyToAddress(pubkeyBytes.toString('hex')); } else if (encoding === 'bech32') { address = starcoin_1.encoding.publicKeyToReceiptIdentifier(pubkeyBytes.toString('hex')); } else { throw new Error('invalid encoding'); } return address; } async signTransaction(unsignedTx, signers) { const [rawTxn, rawUserTransactionBytes] = (0, exports.buildUnsignedRawTx)(unsignedTx, this.chainInfo.implOptions.chainId); const msgBytes = hashRawTx(rawUserTransactionBytes); const { inputs: [{ address: fromAddr, publicKey: senderPublicKey }], } = unsignedTx; (0, precondtion_1.check)(typeof senderPublicKey !== 'undefined', 'senderPublicKey is required'); const [signature] = await signers[fromAddr].sign(Buffer.from(msgBytes)); return (0, exports.buildSignedTx)(senderPublicKey, signature, rawTxn); } async verifyAddress(address) { let isValid = true; let encoding = undefined; let normalizeAddress = address; if (address.startsWith('stc')) { try { const riv = starcoin_1.encoding.decodeReceiptIdentifier(address); normalizeAddress = '0x' + riv.accountAddress; encoding = 'bech32'; } catch (error) { isValid = false; } } else { try { const accountAddress = starcoin_1.encoding.addressToSCS(address); // in order to check invalid address length, because the auto padding 0 at head of address if (starcoin_1.encoding.addressFromSCS(accountAddress) === (address.startsWith('0x') ? address : '0x' + address)) { encoding = 'hex'; } else { isValid = false; } } catch (error) { isValid = false; } } return { normalizedAddress: isValid ? normalizeAddress : undefined, displayAddress: isValid ? address : undefined, isValid, encoding, }; } async signMessage({ message }, signer, address) { const privateKey = await signer.getPrvkey(); const { signature } = await starcoin_1.utils.signedMessage.signMessage(message, privateKey.toString('hex')); return signature; } async verifyMessage(publicKey, // require pubkey here!! { message }, signature) { // starcoin sdk doesn't provide a direct method to verify message, need to // build up a signedMessage ourselves. const messageBytes = new Uint8Array(Buffer.from(message, 'utf8')); const signedMessageHex = await starcoin_1.utils.signedMessage.generateSignedMessage(new starcoin_1.starcoin_types.SigningMessage(messageBytes), parseInt(this.chainInfo.implOptions.chainId), publicKey, signature); try { const address = await starcoin_1.utils.signedMessage.recoverSignedMessageAddress(signedMessageHex); return address === starcoin_1.encoding.publicKeyToAddress(publicKey); } catch (e) { console.error(e); return false; } } async hardwareGetXpubs(paths, showOnDevice) { const resp = await this.wrapHardwareCall(() => js_sdk_1.default.starcoinGetPublicKey({ bundle: paths.map((path) => ({ path, showOnDevice })), })); return resp.map((i) => ({ path: i.serializedPath, xpub: i.publicKey, })); } async hardwareGetAddress(path, showOnDevice, addressToVerify) { const params = { path, showOnDevice, }; if (typeof addressToVerify === 'string') { Object.assign(params, { address: addressToVerify, }); } const { address } = await this.wrapHardwareCall(() => js_sdk_1.default.starcoinGetAddress(params)); return address; } async hardwareSignTransaction(unsignedTx, signers) { const [rawTxn, rawUserTransactionBytes] = (0, exports.buildUnsignedRawTx)(unsignedTx, this.chainInfo.implOptions.chainId); const { inputs: [{ address: fromAddr, publicKey: senderPublicKey }], } = unsignedTx; (0, precondtion_1.check)(typeof senderPublicKey !== 'undefined', 'senderPublicKey is required'); const { signature } = await this.wrapHardwareCall(() => js_sdk_1.default.starcoinSignTransaction({ path: signers[fromAddr], rawTx: Buffer.from(rawUserTransactionBytes).toString('hex'), })); return (0, exports.buildSignedTx)(senderPublicKey, Buffer.from(signature, 'hex'), rawTxn); } async hardwareSignMessage({ message }, signer) { const { signature } = await this.wrapHardwareCall(() => js_sdk_1.default.starcoinSignMessage({ path: signer, message, })); return ethUtil.addHexPrefix(signature); } async hardwareVerifyMessage(publicKey, // require pubkey here!! { message }, signature) { const { message: resp } = await this.wrapHardwareCall(() => js_sdk_1.default.starcoinVerifyMessage({ publicKey, message, signature, })); return resp === 'Message verified'; } } exports.Provider = Provider; const buildUnsignedRawTx = (unsignedTx, chainId) => { const fromAddr = unsignedTx.inputs[0].address; const scriptFn = unsignedTx.payload.scriptFn; const gasLimit = unsignedTx.feeLimit; const gasPrice = unsignedTx.feePricePerUnit; const nonce = unsignedTx.nonce; const expirationTime = unsignedTx.payload.expirationTime; if (!fromAddr || !scriptFn || !gasLimit || !gasPrice || typeof nonce === 'undefined') { throw new Error('invalid unsignedTx'); } const rawTxn = starcoin_1.utils.tx.generateRawUserTransaction(fromAddr, scriptFn, gasLimit.toNumber(), gasPrice.toNumber(), nonce, expirationTime, Number(chainId)); const serializer = new starcoin_1.bcs.BcsSerializer(); rawTxn.serialize(serializer); return [rawTxn, serializer.getBytes()]; }; exports.buildUnsignedRawTx = buildUnsignedRawTx; const hashRawTx = (rawUserTransactionBytes) => { const hashSeedBytes = starcoin_1.crypto_hash.createRawUserTransactionHasher().get_salt(); return Uint8Array.of(...hashSeedBytes, ...rawUserTransactionBytes); }; const buildSignedTx = (senderPublicKey, rawSignature, rawTxn) => { const publicKey = new starcoin_1.starcoin_types.Ed25519PublicKey(Buffer.from(senderPublicKey, 'hex')); const signature = new starcoin_1.starcoin_types.Ed25519Signature(rawSignature); const transactionAuthenticatorVariantEd25519 = new starcoin_1.starcoin_types.TransactionAuthenticatorVariantEd25519(publicKey, signature); const signedUserTransaction = new starcoin_1.starcoin_types.SignedUserTransaction(rawTxn, transactionAuthenticatorVariantEd25519); const se = new starcoin_1.bcs.BcsSerializer(); signedUserTransaction.serialize(se); const txid = starcoin_1.crypto_hash .createUserTransactionHasher() .crypto_hash(se.getBytes()); const rawTx = (0, bytes_1.hexlify)(se.getBytes()); return { txid, rawTx }; }; exports.buildSignedTx = buildSignedTx; //# sourceMappingURL=provider.js.map