UNPKG

@ledgerhq/hw-app-helium

Version:
185 lines (154 loc) 5.48 kB
import Address from "@helium/address"; import { PaymentV2, StakeValidatorV1, TokenBurnV1, TransferValidatorStakeV1, UnstakeValidatorV1, SecurityExchangeV1, TokenType, } from "@helium/transactions"; import BigNumber from "bignumber.js"; import BIPPath from "bip32-path"; import JSLong from "long"; const tokenTypeToInt = tokenType => { if (!tokenType) return 0; switch (tokenType) { default: case "hnt": return TokenType.hnt; case "hst": return TokenType.hst; case "mobile": return TokenType.mobile; case "iot": return TokenType.iot; } }; const serializePath = (path: number[]): Buffer => { const buf = Buffer.alloc(1 + path.length * 4); buf.writeUInt8(path.length, 0); for (const [i, num] of path.entries()) { buf.writeUInt32BE(num, 1 + i * 4); } return buf; }; export const pathToBuffer = (originalPath: string): Buffer => { const path = originalPath .split("/") .map(value => (value.endsWith("'") || value.endsWith("h") ? value : value + "'")) .join("/"); const pathNums: number[] = BIPPath.fromString(path).toPathArray(); return serializePath(pathNums); }; const serializeNumber = (amount: number | BigNumber | undefined): Buffer => { let hex = new BigNumber(amount ?? 0).toString(16); hex = hex.length % 2 ? `0${hex}` : hex; const len = Math.floor(hex.length / 2); if (len > 8) throw "Invalid transaction."; const u8 = new Uint8Array(8); for (let i = 0; i < len; i += 1) u8[len - i - 1] = parseInt(hex.slice(i * 2, i * 2 + 2), 16); return Buffer.from(u8); }; const serializeMemo = (memo: string) => { const memoBuffer = Buffer.from(memo, "base64"); const memoLong = JSLong.fromBytes(Array.from(memoBuffer), true, true); return Buffer.from(memoLong.toBytesLE()); }; export const serializePaymentV2 = (txn: PaymentV2): Buffer => { if (txn.payments.length > 1) throw "multiple payments are not supported"; const { amount, memo } = txn.payments[0]; const payee = txn.payments[0].payee as Address; const tokenType = tokenTypeToInt(txn.payments[0].tokenType); const txSerialized = Buffer.concat([ serializeNumber(amount), serializeNumber(txn.fee), serializeNumber(txn.nonce), Buffer.from([payee.version]), Buffer.from([payee.netType | payee.keyType]), Buffer.from(payee.publicKey), serializeMemo(memo || ""), serializeNumber(tokenType), ]); return Buffer.from(txSerialized); }; export const serializeSecurityExchangeV1 = (txn: SecurityExchangeV1): Buffer => { if (!txn.payee) throw "Payee required"; const payee = txn.payee as Address; const txSerialized = Buffer.concat([ serializeNumber(txn.amount), serializeNumber(txn.fee), serializeNumber(txn.nonce), Buffer.from([payee.version]), Buffer.from([payee.netType | payee.keyType]), Buffer.from(payee.publicKey), ]); return Buffer.from(txSerialized); }; export const serializeTokenBurnV1 = (txn: TokenBurnV1): Buffer => { if (!txn.payee) throw "Payee required"; const payee = txn.payee as Address; const txSerialized = Buffer.concat([ serializeNumber(txn.amount), serializeNumber(txn.fee), serializeNumber(txn.nonce), serializeMemo(txn.memo), Buffer.from([payee.version]), Buffer.from([payee.netType | payee.keyType]), Buffer.from(payee.publicKey), ]); return Buffer.from(txSerialized); }; export const serializeStakeValidatorV1 = (txn: StakeValidatorV1): Buffer => { if (!txn.address) throw "Address required"; const address = txn.address as Address; const txSerialized = Buffer.concat([ serializeNumber(txn.stake), serializeNumber(txn.fee), Buffer.from([address.version]), Buffer.from([address.netType | address.keyType]), Buffer.from(address.publicKey), ]); return Buffer.from(txSerialized); }; export const serializeTransferValidatorStakeV1 = (txn: TransferValidatorStakeV1): Buffer => { if (!txn.newOwner) throw "New owner required"; if (!txn.oldOwner) throw "Old owner required"; if (!txn.newAddress) throw "New address required"; if (!txn.oldAddress) throw "Old address required"; const newOwner = txn.newOwner as Address; const oldOwner = txn.oldOwner as Address; const newAddress = txn.newAddress as Address; const oldAddress = txn.oldAddress as Address; const txSerialized = Buffer.concat([ serializeNumber(txn.stakeAmount), serializeNumber(txn.paymentAmount), serializeNumber(txn.fee), Buffer.from([newOwner.version]), Buffer.from([newOwner.keyType]), Buffer.from(newOwner.publicKey), Buffer.from([oldOwner.version]), Buffer.from([oldOwner.keyType]), Buffer.from(oldOwner.publicKey), Buffer.from([newAddress.version]), Buffer.from([newAddress.keyType]), Buffer.from(newAddress.publicKey), Buffer.from([oldAddress.version]), Buffer.from([oldAddress.netType | oldAddress.keyType]), Buffer.from(oldAddress.publicKey), ]); return Buffer.from(txSerialized); }; export const serializeUnstakeValidatorV1 = (txn: UnstakeValidatorV1): Buffer => { if (!txn.address) throw "Address required"; const address = txn.address as Address; const txSerialized = Buffer.concat([ serializeNumber(txn.stakeAmount), serializeNumber(txn.stakeReleaseHeight), serializeNumber(txn.fee), Buffer.from([address.version]), Buffer.from([address.netType | address.keyType]), Buffer.from(address.publicKey), ]); return Buffer.from(txSerialized); };