@ledgerhq/coin-mina
Version:
113 lines (97 loc) • 3.13 kB
text/typescript
import { BigNumber } from "bignumber.js";
import { Observable } from "rxjs";
import { FeeNotLoaded } from "@ledgerhq/errors";
import type { MinaOperation, MinaSignedTransaction, Transaction } from "../types/common";
import type {
Account,
DeviceId,
SignOperationEvent,
OperationType,
AccountBridge,
} from "@ledgerhq/types-live";
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
import { MinaSignature, MinaSigner } from "../types/signer";
import { SignerContext } from "@ledgerhq/coin-framework/signer";
import { buildTransaction } from "./buildTransaction";
import { reEncodeRawSignature } from "../common-logic";
import invariant from "invariant";
export const buildOptimisticOperation = (
account: Account,
transaction: Transaction,
fee: BigNumber,
): MinaOperation => {
let value = new BigNumber(transaction.amount).plus(fee);
if (transaction.fees?.accountCreationFee.gt(0)) {
value = value.minus(transaction.fees.accountCreationFee);
}
const type: OperationType = "OUT";
const operation: MinaOperation = {
id: encodeOperationId(account.id, "", type),
hash: "",
type,
value,
fee,
blockHash: null,
blockHeight: null,
senders: [account.freshAddress],
recipients: [transaction.recipient].filter(Boolean),
accountId: account.id,
date: new Date(),
extra: {
memo: transaction.memo,
accountCreationFee: transaction.fees.accountCreationFee.toString(),
},
};
return operation;
};
/**
* Sign Transaction with Ledger hardware
*/
export const buildSignOperation =
(signerContext: SignerContext<MinaSigner>): AccountBridge<Transaction>["signOperation"] =>
({
account,
transaction,
deviceId,
}: {
account: Account;
transaction: Transaction;
deviceId: DeviceId;
}): Observable<SignOperationEvent> =>
new Observable(o => {
async function main() {
o.next({ type: "device-signature-requested" });
if (!transaction.fees) {
throw new FeeNotLoaded();
}
const unsigned = await buildTransaction(account, transaction);
const { signature } = (await signerContext(deviceId, signer =>
signer.signTransaction(unsigned),
)) as MinaSignature;
invariant(signature, "signature should be defined if user accepted");
const encodedSignature = reEncodeRawSignature(signature);
const signedTransaction: MinaSignedTransaction = {
transaction: unsigned,
signature: encodedSignature,
};
o.next({ type: "device-signature-granted" });
const operation = buildOptimisticOperation(
account,
transaction,
transaction.fees.fee ?? new BigNumber(0),
);
const signedSerializedTx = JSON.stringify(signedTransaction);
o.next({
type: "signed",
signedOperation: {
operation,
signature: signedSerializedTx,
},
});
}
main().then(
() => o.complete(),
e => o.error(e),
);
});
export default buildSignOperation;