@ledgerhq/coin-canton
Version:
94 lines (81 loc) • 3.12 kB
text/typescript
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),
);
});