UNPKG

virto-signer

Version:

A signer for constructing a signed extrinsic using Pass-provided authenticators

57 lines (56 loc) 2.11 kB
import { Bytes, Option, Struct, u64, u8 } from "scale-ts"; import blake2b from "blake2b"; import { getTypedMetadata } from "./utils.js"; import { mergeUint8 } from "@polkadot-api/utils"; const UncheckedExtrinsic = Struct({ version: u8, prelude: Struct({ extensionVersion: u8, extensions: Bytes(), }), call: Bytes(), }); const PassAuthenticate = Option(Struct({ deviceId: Bytes(), credentials: Bytes(), })); const EXTRINSIC_V5 = 0b0000_0101; const EXTRINSIC_FORMAT_GENERAL = 0b0100_0000; export class PassSigner { authenticator; publicKey; constructor(authenticator) { this.authenticator = authenticator; this.publicKey = blake2b(32) .update(mergeUint8(authenticator.hashedUserId, authenticator.hashedUserId)) .digest(); } async signTx(call, signedExtensions, encodedMetadata, atBlockNumber, hasher) { const metadata = getTypedMetadata(encodedMetadata); const context = u64.enc(BigInt(atBlockNumber)); const hasherFn = hasher ?? ((data) => blake2b(32).update(data).digest()); const extensions = await Promise.all(metadata.extrinsic.signedExtensions.map(async ({ identifier }) => { const signedExtension = signedExtensions[identifier]; if (!signedExtension) throw new Error(`Missing ${identifier} signed extension`); if (identifier === "PassAuthenticate") { signedExtensions[identifier].value = PassAuthenticate.enc({ deviceId: this.authenticator.deviceId, credentials: await this.authenticator.credentials(hasherFn(context)), }); } return signedExtension.value; })); return UncheckedExtrinsic.enc({ version: EXTRINSIC_V5 | EXTRINSIC_FORMAT_GENERAL, prelude: { extensionVersion: 0, extensions: mergeUint8(...extensions), }, call, }); } async signBytes(_) { throw new Error("signBytes not implemented"); } }