"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SigningUtils = exports.LedgerAccount = exports.PrivateKeyAccount = void 0;
/*
 * Copyright 2021 NEM
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
const clime_1 = require("clime");
const symbol_sdk_1 = require("symbol-sdk");
/**
 * Basic signing account that adapts the sdk's account.
 */
class PrivateKeyAccount {
    constructor(account) {
        this.account = account;
        this.address = account.address;
        this.publicKey = account.publicAccount.publicKey;
        this.publicAccount = account.publicAccount;
    }
    async cosignTransaction(transaction, transactionHash) {
        const keyPairEncoded = symbol_sdk_1.KeyPair.createKeyPairFromPrivateKeyString(this.account.privateKey);
        return symbol_sdk_1.Convert.uint8ToHex(symbol_sdk_1.KeyPair.sign(keyPairEncoded, symbol_sdk_1.Convert.hexToUint8(transactionHash)));
    }
    async sign(transaction, generationHash) {
        return this.account.sign(transaction, generationHash);
    }
    encryptMessage(rawMessage, recipientPublicAccount) {
        return Promise.resolve(this.account.encryptMessage(rawMessage, recipientPublicAccount));
    }
    close() {
        //nothing to close
        return Promise.resolve();
    }
}
exports.PrivateKeyAccount = PrivateKeyAccount;
/**
 * Ledger account that can sign by connecting to the device.
 */
class LedgerAccount {
    constructor(ledger, networkType, path, publicKey, isOptinSymbolWallet) {
        this.ledger = ledger;
        this.path = path;
        this.publicKey = publicKey;
        this.isOptinSymbolWallet = isOptinSymbolWallet;
        const symbolNetworkType = networkType;
        this.address = symbol_sdk_1.Address.createFromPublicKey(publicKey, symbolNetworkType);
        this.publicAccount = symbol_sdk_1.PublicAccount.createFromPublicKey(publicKey, symbolNetworkType);
    }
    encryptMessage() {
        throw new clime_1.ExpectedError('Ledger does not allow to encrypt messages yet!');
    }
    async cosignTransaction(transaction, transactionHash) {
        console.log();
        console.log(`Co-signing transaction ${transactionHash} with Ledger account ${this.address.plain()}. Check your device!`);
        return await this.ledger.signCosignatureTransaction(this.path, transaction, transactionHash, this.publicKey, this.isOptinSymbolWallet);
    }
    async sign(transaction, generationHash) {
        console.log();
        console.log(`Signing transaction with Ledger account ${this.address.plain()}. Check your device!`);
        const { payload } = await this.ledger.signTransaction(this.path, transaction, generationHash, this.publicKey, false);
        const generationHashBytes = Array.from(symbol_sdk_1.Convert.hexToUint8(generationHash));
        return new symbol_sdk_1.SignedTransaction(payload, symbol_sdk_1.Transaction.createTransactionHash(payload, generationHashBytes), this.publicKey, transaction.type, transaction.networkType);
    }
    close() {
        return this.ledger.close();
    }
}
exports.LedgerAccount = LedgerAccount;
/**
 * Utility object to sign transactions asynchronously
 */
class SigningUtils {
    static async signTransactionWithCosignatories(initiatorAccount, transaction, cosignatories, generationHash) {
        const signedTransaction = await initiatorAccount.sign(transaction, generationHash);
        let signedPayload = signedTransaction.payload;
        for (const cosigner of cosignatories) {
            const signature = await cosigner.cosignTransaction(transaction, signedTransaction.hash);
            symbol_sdk_1.Convert.validateHexString(signature, 128, 'Cosignature is not valid hex!');
            signedPayload += symbol_sdk_1.UInt64.fromUint(0).toHex() + cosigner.publicKey + signature;
        }
        // Calculate new size
        const size = `00000000${(signedPayload.length / 2).toString(16)}`;
        const formatedSize = size.substr(size.length - 8, size.length);
        const littleEndianSize = formatedSize.substr(6, 2) + formatedSize.substr(4, 2) + formatedSize.substr(2, 2) + formatedSize.substr(0, 2);
        signedPayload = littleEndianSize + signedPayload.substr(8, signedPayload.length - 8);
        return new symbol_sdk_1.SignedTransaction(signedPayload, signedTransaction.hash, initiatorAccount.publicKey, transaction.type, transaction.networkType);
    }
}
exports.SigningUtils = SigningUtils;
