"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handlers = void 0;
/* eslint-disable no-console */
const wallet_api_server_1 = require("@ledgerhq/wallet-api-server");
const wallet_api_core_1 = require("@ledgerhq/wallet-api-core");
const index_1 = require("@ledgerhq/coin-framework/account/index");
const cryptoassets_1 = require("@ledgerhq/cryptoassets");
const converters_1 = require("../converters");
const bridge_1 = require("../../bridge");
const errors_1 = require("@ledgerhq/errors");
const live_env_1 = require("@ledgerhq/live-env");
const handlers = ({ accounts, tracking, manifest, uiHooks: { "custom.acre.messageSign": uiMessageSign, "custom.acre.transactionSign": uiTransactionSign, "custom.acre.transactionBroadcast": uiTransactionBroadcast, }, }) => {
    function signTransaction({ accountId: walletAccountId, rawTransaction, options, tokenCurrency, }) {
        const transaction = (0, wallet_api_core_1.deserializeTransaction)(rawTransaction);
        tracking.signTransactionRequested(manifest);
        if (!transaction) {
            tracking.signTransactionFail(manifest);
            return Promise.reject(new Error("Transaction required"));
        }
        const accountId = (0, converters_1.getAccountIdFromWalletAccountId)(walletAccountId);
        if (!accountId) {
            tracking.signTransactionFail(manifest);
            return Promise.reject(new Error(`accountId ${walletAccountId} unknown`));
        }
        const account = accounts.find(account => account.id === accountId);
        if (!account) {
            tracking.signTransactionFail(manifest);
            return Promise.reject(new Error("Account required"));
        }
        const parentAccount = (0, index_1.getParentAccount)(account, accounts);
        const accountFamily = (0, index_1.isTokenAccount)(account)
            ? account.token.parentCurrency.family
            : account.currency.family;
        const mainAccount = (0, index_1.getMainAccount)(account, parentAccount);
        const currency = tokenCurrency ? (0, cryptoassets_1.findTokenById)(tokenCurrency) : null;
        const signerAccount = currency ? (0, index_1.makeEmptyTokenAccount)(mainAccount, currency) : account;
        const { canEditFees, liveTx, hasFeesProvided } = (0, converters_1.getWalletAPITransactionSignFlowInfos)({
            walletApiTransaction: transaction,
            account,
        });
        if (accountFamily !== liveTx.family) {
            return Promise.reject(new Error(`Account and transaction must be from the same family. Account family: ${accountFamily}, Transaction family: ${liveTx.family}`));
        }
        const signFlowInfos = {
            canEditFees,
            liveTx,
            hasFeesProvided,
        };
        return new Promise((resolve, reject) => {
            let done = false;
            return uiTransactionSign({
                account: signerAccount,
                parentAccount,
                signFlowInfos,
                options,
                onSuccess: signedOperation => {
                    if (done)
                        return;
                    done = true;
                    tracking.signTransactionSuccess(manifest);
                    resolve(signedOperation);
                },
                onError: error => {
                    if (done)
                        return;
                    done = true;
                    tracking.signTransactionFail(manifest);
                    reject(error);
                },
            });
        });
    }
    return {
        "custom.acre.messageSign": (0, wallet_api_server_1.customWrapper)(async (params) => {
            if (!params) {
                tracking.signMessageNoParams(manifest);
                // Maybe return an error instead
                return { hexSignedMessage: "" };
            }
            tracking.signMessageRequested(manifest);
            const { accountId: walletAccountId, derivationPath, message, options } = params;
            const accountId = (0, converters_1.getAccountIdFromWalletAccountId)(walletAccountId);
            if (!accountId) {
                tracking.signMessageFail(manifest);
                return Promise.reject(new Error(`accountId ${walletAccountId} unknown`));
            }
            const account = accounts.find(account => account.id === accountId);
            if (account === undefined) {
                tracking.signMessageFail(manifest);
                return Promise.reject(new Error("account not found"));
            }
            const path = fromRelativePath((0, index_1.getMainAccount)(account).freshAddressPath, derivationPath);
            const formattedMessage = { ...message, path };
            return new Promise((resolve, reject) => {
                let done = false;
                return uiMessageSign({
                    account,
                    message: formattedMessage,
                    options,
                    onSuccess: signature => {
                        if (done)
                            return;
                        done = true;
                        tracking.signMessageSuccess(manifest);
                        resolve({
                            hexSignedMessage: signature.replace("0x", ""),
                        });
                    },
                    onCancel: () => {
                        if (done)
                            return;
                        done = true;
                        tracking.signMessageFail(manifest);
                        reject(new errors_1.UserRefusedOnDevice());
                    },
                    onError: error => {
                        if (done)
                            return;
                        done = true;
                        tracking.signMessageFail(manifest);
                        reject(error);
                    },
                });
            });
        }),
        "custom.acre.transactionSign": (0, wallet_api_server_1.customWrapper)(async (params) => {
            if (!params) {
                tracking.signTransactionNoParams(manifest);
                // Maybe return an error instead
                return { signedTransactionHex: "" };
            }
            const signedOperation = await signTransaction(params);
            return {
                signedTransactionHex: Buffer.from(signedOperation.signature).toString("hex"),
            };
        }),
        "custom.acre.transactionSignAndBroadcast": (0, wallet_api_server_1.customWrapper)(async (params) => {
            if (!params) {
                tracking.signTransactionAndBroadcastNoParams(manifest);
                // Maybe return an error instead
                return { transactionHash: "" };
            }
            const signedOperation = await signTransaction(params);
            if (!signedOperation) {
                tracking.broadcastFail(manifest);
                return Promise.reject(new Error("Transaction required"));
            }
            const { accountId: walletAccountId, tokenCurrency } = params;
            const accountId = (0, converters_1.getAccountIdFromWalletAccountId)(walletAccountId);
            if (!accountId) {
                tracking.broadcastFail(manifest);
                return Promise.reject(new Error(`accountId ${walletAccountId} unknown`));
            }
            const account = accounts.find(account => account.id === accountId);
            if (!account) {
                tracking.broadcastFail(manifest);
                return Promise.reject(new Error("Account required"));
            }
            const currency = tokenCurrency ? (0, cryptoassets_1.findTokenById)(tokenCurrency) : null;
            const parentAccount = (0, index_1.getParentAccount)(account, accounts);
            const mainAccount = (0, index_1.getMainAccount)(account, parentAccount);
            const signerAccount = currency ? (0, index_1.makeEmptyTokenAccount)(mainAccount, currency) : account;
            const bridge = (0, bridge_1.getAccountBridge)(signerAccount, parentAccount);
            const broadcastAccount = (0, index_1.getMainAccount)(signerAccount, parentAccount);
            let optimisticOperation = signedOperation.operation;
            if (!(0, live_env_1.getEnv)("DISABLE_TRANSACTION_BROADCAST")) {
                try {
                    optimisticOperation = await bridge.broadcast({
                        account: broadcastAccount,
                        signedOperation,
                    });
                    tracking.broadcastSuccess(manifest);
                }
                catch (error) {
                    tracking.broadcastFail(manifest);
                    throw error;
                }
            }
            uiTransactionBroadcast &&
                uiTransactionBroadcast(account, parentAccount, mainAccount, optimisticOperation);
            return {
                transactionHash: optimisticOperation.hash,
            };
        }),
    };
};
exports.handlers = handlers;
function fromRelativePath(basePath, derivationPath) {
    if (!derivationPath) {
        return basePath;
    }
    const splitPath = basePath.split("'/");
    splitPath[splitPath.length - 1] = derivationPath;
    return splitPath.join("'/");
}
//# sourceMappingURL=server.js.map