var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { Buffer } from 'buffer';
import * as ed25519 from '@noble/ed25519';
import { sha512 } from '@noble/hashes/sha512';
import { Keypair } from '@solarti/web3.js';
import { UninitializedDerivedIdentityError } from './errors';
import { isSigner, subtractAmounts, } from '../../types';
/**
 * @group Modules
 */
export class DerivedIdentityClient {
    constructor(metaplex) {
        this.originalSigner = null;
        this.derivedKeypair = null;
        this.metaplex = metaplex;
    }
    get publicKey() {
        this.assertInitialized();
        return this.derivedKeypair.publicKey;
    }
    get secretKey() {
        this.assertInitialized();
        return this.derivedKeypair.secretKey;
    }
    get originalPublicKey() {
        this.assertInitialized();
        return this.originalSigner.publicKey;
    }
    deriveFrom(message, originalSigner) {
        return __awaiter(this, void 0, void 0, function* () {
            this.originalSigner = originalSigner !== null && originalSigner !== void 0 ? originalSigner : this.metaplex.identity().driver();
            const signature = yield this.originalSigner.signMessage(Buffer.from(message));
            const seeds = sha512(signature).slice(0, 32);
            this.derivedKeypair = Keypair.fromSeed(seeds);
        });
    }
    fund(amount) {
        this.assertInitialized();
        return this.metaplex.system().transferSol({
            from: this.originalSigner,
            to: this.derivedKeypair.publicKey,
            amount,
        }, { payer: this.originalSigner });
    }
    withdraw(amount) {
        this.assertInitialized();
        return this.metaplex.system().transferSol({
            from: this.derivedKeypair,
            to: this.originalSigner.publicKey,
            amount,
        }, { payer: this.derivedKeypair });
    }
    withdrawAll() {
        return __awaiter(this, void 0, void 0, function* () {
            this.assertInitialized();
            const balance = yield this.metaplex
                .rpc()
                .getBalance(this.derivedKeypair.publicKey);
            const transactionFee = this.metaplex.utils().estimateTransactionFee();
            return this.withdraw(subtractAmounts(balance, transactionFee));
        });
    }
    close() {
        this.originalSigner = null;
        this.derivedKeypair = null;
    }
    signMessage(message) {
        return __awaiter(this, void 0, void 0, function* () {
            return ed25519.sync.sign(message, this.secretKey);
        });
    }
    signTransaction(transaction) {
        return __awaiter(this, void 0, void 0, function* () {
            transaction.partialSign(this);
            return transaction;
        });
    }
    signAllTransactions(transactions) {
        return __awaiter(this, void 0, void 0, function* () {
            return Promise.all(transactions.map((transaction) => this.signTransaction(transaction)));
        });
    }
    verifyMessage(message, signature) {
        return ed25519.sync.verify(message, signature, this.publicKey.toBytes());
    }
    equals(that) {
        if (isSigner(that)) {
            that = that.publicKey;
        }
        return this.publicKey.equals(that);
    }
    assertInitialized() {
        if (this.derivedKeypair === null || this.originalSigner === null) {
            throw new UninitializedDerivedIdentityError();
        }
    }
}
//# sourceMappingURL=DerivedIdentityClient.js.map