UNPKG

@ledgerhq/coin-canton

Version:
94 lines (81 loc) 3.12 kB
import { Observable } from "rxjs"; import { FeeNotLoaded } from "@ledgerhq/errors"; import { AccountBridge, Operation } from "@ledgerhq/types-live"; import { SignerContext } from "@ledgerhq/coin-framework/signer"; import { encodeOperationId } from "@ledgerhq/coin-framework/operation"; import { combine, craftTransaction, getNextValidSequence } from "../common-logic"; import { Transaction, CantonSigner, BoilerplateNativeTransaction } from "../types"; export const buildSignOperation = (signerContext: SignerContext<CantonSigner>): AccountBridge<Transaction>["signOperation"] => ({ account, deviceId, transaction }) => new Observable(o => { async function main() { const { fee } = transaction; if (!fee) throw new FeeNotLoaded(); try { // o observables allows to define steps of the signing process with the device o.next({ type: "device-signature-requested", }); const nextSequenceNumber = await getNextValidSequence(account.freshAddress); const signature = await signerContext(deviceId, async signer => { const { freshAddressPath: derivationPath } = account; const { publicKey } = await signer.getAddress(derivationPath); const { nativeTransaction, serializedTransaction } = await craftTransaction( { address: account.freshAddress, publicKey, }, { recipient: transaction.recipient, amount: transaction.amount, fee: fee, }, ); const transactionSignature = await signer.signTransaction( derivationPath, serializedTransaction, ); return combine(serializedTransaction, transactionSignature, publicKey); }); o.next({ type: "device-signature-granted", }); // We create an optimistic operation here, the framework will then replace this transaction with the one returned by the indexer const hash = ""; const operation: Operation = { id: encodeOperationId(account.id, hash, "OUT"), hash, accountId: account.id, type: "OUT", value: transaction.amount, fee, blockHash: null, blockHeight: null, senders: [account.freshAddress], recipients: [transaction.recipient], date: new Date(), transactionSequenceNumber: nextSequenceNumber, extra: {}, }; o.next({ type: "signed", signedOperation: { operation, signature, }, }); } catch (e) { if (e instanceof Error) { throw new Error( (e as Error & { data?: { resultMessage?: string } })?.data?.resultMessage, ); } throw e; } } main().then( () => o.complete(), e => o.error(e), ); });