@ledgerhq/coin-celo
Version:
85 lines • 3.99 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildSignOperation = void 0;
const bignumber_js_1 = require("bignumber.js");
const rxjs_1 = require("rxjs");
const errors_1 = require("@ledgerhq/errors");
const wallet_base_1 = require("@celo/wallet-base");
const index_1 = require("@ledgerhq/coin-framework/account/index");
const buildOptimisticOperation_1 = require("./buildOptimisticOperation");
const buildTransaction_1 = __importDefault(require("./buildTransaction"));
const sdk_1 = require("../network/sdk");
/**
* Sign Transaction with Ledger hardware
*/
const buildSignOperation = (signerContext) => ({ account, transaction, deviceId, }) => new rxjs_1.Observable(o => {
let cancelled;
async function main() {
const { fees } = transaction;
if (!fees)
throw new errors_1.FeeNotLoaded();
const unsignedTransaction = await (0, buildTransaction_1.default)(account, transaction);
const { chainId, to } = unsignedTransaction;
const subAccount = (0, index_1.findSubAccountById)(account, transaction.subAccountId ?? "");
const isTokenTransaction = subAccount?.type === "TokenAccount";
await signerContext(deviceId, signer => {
return signer.verifyTokenInfo(isTokenTransaction ? subAccount.token.contractAddress : to, chainId);
});
const finalTransaction = {
...unsignedTransaction,
to: isTokenTransaction ? subAccount.token.contractAddress : to,
value: isTokenTransaction ? 0 : unsignedTransaction.value,
};
await (0, sdk_1.determineFees)(finalTransaction);
const rlpEncodedTransaction = await signerContext(deviceId, signer => {
return signer.rlpEncodedTxForLedger(finalTransaction);
});
o.next({ type: "device-signature-requested" });
const response = (await signerContext(deviceId, signer => {
return signer.signTransaction(account.freshAddressPath, trimLeading0x(rlpEncodedTransaction.rlpEncode));
}));
const { address } = await signerContext(deviceId, signer => {
return signer.getAddress(account.freshAddressPath);
});
const convertedResponse = { ...response, v: response.v.toString() };
if (cancelled)
return;
const signature = parseSigningResponse(convertedResponse, chainId);
o.next({ type: "device-signature-granted" });
const encodedTransaction = await (0, wallet_base_1.encodeTransaction)(rlpEncodedTransaction, signature);
const [_, recoveredAddress] = (0, wallet_base_1.recoverTransaction)(encodedTransaction.raw);
if (recoveredAddress !== address) {
throw new Error("celo: there was a signing error, the recovered address doesn't match the your ledger address, the operation was cancelled");
}
const operation = (0, buildOptimisticOperation_1.buildOptimisticOperation)(account, transaction, transaction.fees ?? new bignumber_js_1.BigNumber(0));
o.next({
type: "signed",
signedOperation: {
operation,
signature: encodedTransaction.raw,
},
});
}
main().then(() => o.complete(), e => o.error(e));
return () => {
cancelled = true;
};
});
exports.buildSignOperation = buildSignOperation;
const trimLeading0x = (input) => (input.startsWith("0x") ? input.slice(2) : input);
const parseSigningResponse = (response, chainId) => {
// EIP155
const sigV = parseInt(response.v, 16);
let eip155V = chainId * 2 + 35;
eip155V = sigV;
return {
s: Buffer.from(response.s, "hex"),
v: eip155V,
r: Buffer.from(response.r, "hex"),
};
};
exports.default = exports.buildSignOperation;
//# sourceMappingURL=signOperation.js.map