"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StorageProvider = void 0;
exports.validateStorageFeeModel = validateStorageFeeModel;
const sdk_1 = require("@bsv/sdk");
const getBeefForTransaction_1 = require("./methods/getBeefForTransaction");
const processAction_1 = require("./methods/processAction");
const attemptToPostReqsToNetwork_1 = require("./methods/attemptToPostReqsToNetwork");
const listCertificates_1 = require("./methods/listCertificates");
const createAction_1 = require("./methods/createAction");
const internalizeAction_1 = require("./methods/internalizeAction");
const StorageReaderWriter_1 = require("./StorageReaderWriter");
const entities_1 = require("./schema/entities");
const WERR_errors_1 = require("../sdk/WERR_errors");
const utilityHelpers_1 = require("../utility/utilityHelpers");
const WalletError_1 = require("../sdk/WalletError");
const utilityHelpers_noBuffer_1 = require("../utility/utilityHelpers.noBuffer");
class StorageProvider extends StorageReaderWriter_1.StorageReaderWriter {
    static defaultOptions() {
        return {
            feeModel: { model: 'sat/kb', value: 1 },
            commissionSatoshis: 0,
            commissionPubKeyHex: undefined
        };
    }
    static createStorageBaseOptions(chain) {
        const options = {
            ...StorageProvider.defaultOptions(),
            chain
        };
        return options;
    }
    constructor(options) {
        super(options);
        this.isDirty = false;
        this.feeModel = options.feeModel;
        this.commissionPubKeyHex = options.commissionPubKeyHex;
        this.commissionSatoshis = options.commissionSatoshis;
        this.maxRecursionDepth = 12;
    }
    async findOutputsByIds(outputIds, trx) {
        const byId = {};
        for (const outputId of outputIds) {
            const o = (0, utilityHelpers_1.verifyOneOrNone)(await this.findOutputs({ partial: { outputId }, trx }));
            if ((o === null || o === void 0 ? void 0 : o.outputId) !== undefined)
                byId[o.outputId] = o;
        }
        return byId;
    }
    async findStaleMerkleRoots(args) {
        let provenTxs = await this.findProvenTxs({ partial: { height: args.height } });
        provenTxs = provenTxs.filter(ptx => ptx.merkleRoot !== args.merkleRoot);
        let roots = Array.from(new Set(provenTxs.map(ptx => ptx.merkleRoot)));
        return roots;
    }
    async findOutputsByOutpoints(userId, outpoints, trx) {
        const byOutpoint = {};
        for (const { txid, vout } of outpoints) {
            const o = (0, utilityHelpers_1.verifyOneOrNone)(await this.findOutputs({ partial: { userId, txid, vout }, trx }));
            if ((o === null || o === void 0 ? void 0 : o.txid) !== undefined && o.vout !== undefined)
                byOutpoint[`${o.txid}.${o.vout}`] = o;
        }
        return byOutpoint;
    }
    async findOrInsertOutputBasketsBulk(userId, names, trx) {
        const byName = {};
        for (const name of names)
            byName[name] = await this.findOrInsertOutputBasket(userId, name, trx);
        return byName;
    }
    async findOrInsertOutputTagsBulk(userId, tags, trx) {
        const byTag = {};
        for (const tag of tags)
            byTag[tag] = await this.findOrInsertOutputTag(userId, tag, trx);
        return byTag;
    }
    async sumSpendableSatoshisInBasket(userId, basketId, excludeSending, trx) {
        const status = ['completed', 'unproven'];
        if (!excludeSending)
            status.push('sending');
        const rows = await this.findOutputs({
            partial: { userId, spendable: true, basketId },
            txStatus: status,
            noScript: true,
            trx
        });
        return rows.reduce((a, r) => a + Number(r.satoshis || 0), 0);
    }
    isStorageProvider() {
        return true;
    }
    setServices(v) {
        this._services = v;
    }
    getServices() {
        if (!this._services)
            throw new WERR_errors_1.WERR_INVALID_OPERATION('Must setServices first.');
        return this._services;
    }
    async abortAction(auth, args) {
        if (!auth.userId)
            throw new WERR_errors_1.WERR_INVALID_PARAMETER('auth.userId', 'valid');
        const userId = auth.userId;
        let reference = args.reference;
        let txid = undefined;
        const r = await this.transaction(async (trx) => {
            let tx = (0, utilityHelpers_1.verifyOneOrNone)(await this.findTransactions({
                partial: { reference, userId },
                noRawTx: true,
                trx
            }));
            if (!tx && args.reference.length === 64) {
                // reference may also be a txid
                txid = reference;
                reference = undefined;
                tx = (0, utilityHelpers_1.verifyOneOrNone)(await this.findTransactions({
                    partial: { txid, userId },
                    noRawTx: true,
                    trx
                }));
            }
            const unAbortableStatus = ['completed', 'failed', 'sending', 'unproven'];
            if (!tx || !tx.isOutgoing || -1 < unAbortableStatus.findIndex(s => s === tx.status))
                throw new WERR_errors_1.WERR_INVALID_PARAMETER('reference', 'an inprocess, outgoing action that has not been signed and shared to the network.');
            await this.updateTransactionStatus('failed', tx.transactionId, userId, reference, trx);
            if (tx.txid) {
                const req = await entities_1.EntityProvenTxReq.fromStorageTxid(this, tx.txid, trx);
                if (req) {
                    req.addHistoryNote({ what: 'abortAction', reference: args.reference });
                    req.status = 'invalid';
                    await req.updateStorageDynamicProperties(this, trx);
                }
            }
            const r = {
                aborted: true
            };
            return r;
        });
        return r;
    }
    async internalizeAction(auth, args) {
        return await (0, internalizeAction_1.internalizeAction)(this, auth, args);
    }
    /**
     * Given an array of transaction txids with current ProvenTxReq ready-to-share status,
     * lookup their ProvenTxReqApi req records.
     * For the txids with reqs and status still ready to send construct a single merged beef.
     *
     * @param txids
     * @param knownTxids
     * @param trx
     */
    async getReqsAndBeefToShareWithWorld(txids, knownTxids, trx) {
        const r = {
            beef: new sdk_1.Beef(),
            details: []
        };
        for (const txid of txids) {
            const d = {
                txid,
                // status: 'readyToSend' | 'alreadySent' | 'error' | 'unknown'
                status: 'unknown'
                // req?: TableProvenTxReq
                // proven?: TableProvenTx
                // error?: string
            };
            r.details.push(d);
            try {
                d.proven = (0, utilityHelpers_1.verifyOneOrNone)(await this.findProvenTxs({ partial: { txid }, trx }));
                if (d.proven)
                    d.status = 'alreadySent';
                else {
                    const alreadySentStatus = ['unmined', 'callback', 'unconfirmed', 'completed'];
                    const readyToSendStatus = ['sending', 'unsent', 'nosend', 'unprocessed'];
                    const errorStatus = ['unknown', 'nonfinal', 'invalid', 'doubleSpend'];
                    d.req = (0, utilityHelpers_1.verifyOneOrNone)(await this.findProvenTxReqs({ partial: { txid }, trx }));
                    if (!d.req) {
                        d.status = 'error';
                        d.error = `ERR_UNKNOWN_TXID: ${txid} was not found.`;
                    }
                    else if (errorStatus.indexOf(d.req.status) > -1) {
                        d.status = 'error';
                        d.error = `ERR_INVALID_PARAMETER: ${txid} is not ready to send.`;
                    }
                    else if (alreadySentStatus.indexOf(d.req.status) > -1) {
                        d.status = 'alreadySent';
                    }
                    else if (readyToSendStatus.indexOf(d.req.status) > -1) {
                        if (!d.req.rawTx || !d.req.inputBEEF) {
                            d.status = 'error';
                            d.error = `ERR_INTERNAL: ${txid} req is missing rawTx or beef.`;
                        }
                        else
                            d.status = 'readyToSend';
                    }
                    else {
                        d.status = 'error';
                        d.error = `ERR_INTERNAL: ${txid} has unexpected req status ${d.req.status}`;
                    }
                    if (d.status === 'readyToSend') {
                        await this.mergeReqToBeefToShareExternally(d.req, r.beef, knownTxids, trx);
                    }
                }
            }
            catch (eu) {
                const e = WalletError_1.WalletError.fromUnknown(eu);
                d.error = `${e.name}: ${e.message}`;
            }
        }
        return r;
    }
    async mergeReqToBeefToShareExternally(req, mergeToBeef, knownTxids, trx) {
        const { rawTx, inputBEEF: beef } = req;
        if (!rawTx || !beef)
            throw new WERR_errors_1.WERR_INTERNAL(`req rawTx and beef must be valid.`);
        mergeToBeef.mergeRawTx((0, utilityHelpers_noBuffer_1.asArray)(rawTx));
        mergeToBeef.mergeBeef((0, utilityHelpers_noBuffer_1.asArray)(beef));
        const tx = sdk_1.Transaction.fromBinary((0, utilityHelpers_noBuffer_1.asArray)(rawTx));
        for (const input of tx.inputs) {
            if (!input.sourceTXID)
                throw new WERR_errors_1.WERR_INTERNAL(`req all transaction inputs must have valid sourceTXID`);
            const txid = input.sourceTXID;
            const btx = mergeToBeef.findTxid(txid);
            if (!btx) {
                if (knownTxids && knownTxids.indexOf(txid) > -1)
                    mergeToBeef.mergeTxidOnly(txid);
                else
                    await this.getValidBeefForKnownTxid(txid, mergeToBeef, undefined, knownTxids, trx);
            }
        }
    }
    /**
     * Checks if txid is a known valid ProvenTx and returns it if found.
     * Next checks if txid is a current ProvenTxReq and returns that if found.
     * If `newReq` is provided and an existing ProvenTxReq isn't found,
     * use `newReq` to create a new ProvenTxReq.
     *
     * This is safe "findOrInsert" operation using retry if unique index constraint
     * is violated by a race condition insert.
     *
     * @param txid
     * @param newReq
     * @param trx
     * @returns
     */
    async getProvenOrReq(txid, newReq, trx) {
        if (newReq && txid !== newReq.txid)
            throw new WERR_errors_1.WERR_INVALID_PARAMETER('newReq', `same txid`);
        const r = { proven: undefined, req: undefined };
        r.proven = (0, utilityHelpers_1.verifyOneOrNone)(await this.findProvenTxs({ partial: { txid }, trx }));
        if (r.proven)
            return r;
        for (let retry = 0;; retry++) {
            try {
                r.req = (0, utilityHelpers_1.verifyOneOrNone)(await this.findProvenTxReqs({ partial: { txid }, trx }));
                if (!r.req && !newReq)
                    break;
                if (!r.req && newReq) {
                    await this.insertProvenTxReq(newReq, trx);
                }
                if (r.req && newReq) {
                    // Merge history and notify into existing
                    const req1 = new entities_1.EntityProvenTxReq(r.req);
                    req1.mergeHistory(newReq, undefined, true);
                    req1.mergeNotifyTransactionIds(newReq);
                    await req1.updateStorageDynamicProperties(this, trx);
                }
                break;
            }
            catch (eu) {
                if (retry > 0)
                    throw eu;
            }
        }
        return r;
    }
    async updateTransactionsStatus(transactionIds, status, trx) {
        await this.transaction(async (trx) => {
            for (const id of transactionIds) {
                await this.updateTransactionStatus(status, id, undefined, undefined, trx);
            }
        }, trx);
    }
    /**
     * For all `status` values besides 'failed', just updates the transaction records status property.
     *
     * For 'status' of 'failed', attempts to make outputs previously allocated as inputs to this transaction usable again.
     *
     * @param status
     * @param transactionId
     * @param userId
     * @param reference
     * @param trx
     */
    async updateTransactionStatus(status, transactionId, userId, reference, trx) {
        if (!transactionId && !(userId && reference))
            throw new WERR_errors_1.WERR_MISSING_PARAMETER('either transactionId or userId and reference');
        await this.transaction(async (trx) => {
            const where = {};
            if (transactionId)
                where.transactionId = transactionId;
            if (userId)
                where.userId = userId;
            if (reference)
                where.reference = reference;
            const tx = (0, utilityHelpers_1.verifyOne)(await this.findTransactions({ partial: where, noRawTx: true, trx }));
            //if (tx.status === status)
            // no change required. Assume inputs and outputs spendable and spentBy are valid for status.
            //return
            // Once completed, this method cannot be used to "uncomplete" transaction.
            if ((status !== 'completed' && tx.status === 'completed') || tx.provenTxId)
                throw new WERR_errors_1.WERR_INVALID_OPERATION('The status of a "completed" transaction cannot be changed.');
            // It is not possible to un-fail a transaction. Information is lost and not recoverable.
            if (status !== 'failed' && tx.status === 'failed')
                throw new WERR_errors_1.WERR_INVALID_OPERATION(`A "failed" transaction may not be un-failed by this method.`);
            switch (status) {
                case 'failed':
                    {
                        // Attempt to make outputs previously allocated as inputs to this transaction usable again.
                        // Only clear input's spentBy and reset spendable = true if it references this transaction
                        const t = new entities_1.EntityTransaction(tx);
                        const inputs = await t.getInputs(this, trx);
                        for (const input of inputs) {
                            // input is a prior output belonging to userId that reference this transaction either by `spentBy`
                            // or by txid and vout.
                            await this.updateOutput((0, utilityHelpers_1.verifyId)(input.outputId), { spendable: true, spentBy: undefined }, trx);
                        }
                    }
                    break;
                case 'nosend':
                case 'unsigned':
                case 'unprocessed':
                case 'sending':
                case 'unproven':
                case 'completed':
                    break;
                default:
                    throw new WERR_errors_1.WERR_INVALID_PARAMETER('status', `not be ${status}`);
            }
            await this.updateTransaction(tx.transactionId, { status }, trx);
        }, trx);
    }
    async createAction(auth, args) {
        if (!auth.userId)
            throw new WERR_errors_1.WERR_UNAUTHORIZED();
        return await (0, createAction_1.createAction)(this, auth, args);
    }
    async processAction(auth, args) {
        if (!auth.userId)
            throw new WERR_errors_1.WERR_UNAUTHORIZED();
        return await (0, processAction_1.processAction)(this, auth, args);
    }
    async attemptToPostReqsToNetwork(reqs, trx, logger) {
        return await (0, attemptToPostReqsToNetwork_1.attemptToPostReqsToNetwork)(this, reqs, trx, logger);
    }
    async listCertificates(auth, args) {
        return await (0, listCertificates_1.listCertificates)(this, auth, args);
    }
    async verifyKnownValidTransaction(txid, trx) {
        const { proven, rawTx } = await this.getProvenOrRawTx(txid, trx);
        return proven != undefined || rawTx != undefined;
    }
    /**
     * Pulls data from storage to build a valid beef for a txid.
     *
     * Optionally merges the data into an existing beef.
     * Optionally requires a minimum number of proof levels.
     *
     * @param txid
     * @param mergeToBeef
     * @param trustSelf
     * @param knownTxids
     * @param trx
     * @param requiredLevels
     * @returns
     */
    async getValidBeefForKnownTxid(txid, mergeToBeef, trustSelf, knownTxids, trx, requiredLevels) {
        const beef = await this.getValidBeefForTxid(txid, mergeToBeef, trustSelf, knownTxids, trx, requiredLevels);
        if (!beef)
            throw new WERR_errors_1.WERR_INVALID_PARAMETER('txid', `known to storage. ${txid} is not known.`);
        return beef;
    }
    async getValidBeefForTxid(txid, mergeToBeef, trustSelf, knownTxids, trx, requiredLevels, chainTracker, skipInvalidProofs) {
        const beef = mergeToBeef || new sdk_1.Beef();
        const r = await this.getProvenOrRawTx(txid, trx);
        if (r.proven) {
            if (requiredLevels) {
                r.rawTx = r.proven.rawTx;
            }
            else {
                if (trustSelf === 'known')
                    beef.mergeTxidOnly(txid);
                else {
                    const mp = new entities_1.EntityProvenTx(r.proven).getMerklePath();
                    if (chainTracker) {
                        const root = mp.computeRoot();
                        const isValid = await chainTracker.isValidRootForHeight(root, r.proven.height);
                        if (!isValid) {
                            if (!skipInvalidProofs) {
                                throw new WERR_errors_1.WERR_INVALID_MERKLE_ROOT(r.proven.blockHash, r.proven.height, root, txid);
                            }
                            // ignore this currently invalid proof and try to recurse deeper
                            r.rawTx = r.proven.rawTx;
                            r.proven = undefined;
                        }
                    }
                    if (r.proven) {
                        // If we still like this proof, merge it and return
                        beef.mergeRawTx(r.proven.rawTx);
                        beef.mergeBump(mp);
                        return beef;
                    }
                }
            }
        }
        if (!r.rawTx)
            return undefined;
        if (trustSelf === 'known') {
            beef.mergeTxidOnly(txid);
        }
        else {
            beef.mergeRawTx(r.rawTx);
            if (r.inputBEEF)
                beef.mergeBeef(r.inputBEEF);
            const tx = sdk_1.Transaction.fromBinary(r.rawTx);
            if (requiredLevels)
                requiredLevels--;
            for (const input of tx.inputs) {
                const btx = beef.findTxid(input.sourceTXID);
                if (!btx) {
                    if (!requiredLevels && knownTxids && knownTxids.indexOf(input.sourceTXID) > -1)
                        beef.mergeTxidOnly(input.sourceTXID);
                    else
                        await this.getValidBeefForKnownTxid(input.sourceTXID, beef, trustSelf, knownTxids, trx, requiredLevels);
                }
            }
        }
        return beef;
    }
    async getBeefForTransaction(txid, options) {
        const beef = await (0, getBeefForTransaction_1.getBeefForTransaction)(this, txid, options);
        return beef;
    }
    async findMonitorEventById(id, trx) {
        return (0, utilityHelpers_1.verifyOneOrNone)(await this.findMonitorEvents({ partial: { id }, trx }));
    }
    async relinquishCertificate(auth, args) {
        const vargs = sdk_1.Validation.validateRelinquishCertificateArgs(args);
        const cert = (0, utilityHelpers_1.verifyOne)(await this.findCertificates({
            partial: {
                certifier: vargs.certifier,
                serialNumber: vargs.serialNumber,
                type: vargs.type
            }
        }));
        return await this.updateCertificate(cert.certificateId, {
            isDeleted: true
        });
    }
    async relinquishOutput(auth, args) {
        const vargs = sdk_1.Validation.validateRelinquishOutputArgs(args);
        const { txid, vout } = sdk_1.Validation.parseWalletOutpoint(vargs.output);
        const output = (0, utilityHelpers_1.verifyOne)(await this.findOutputs({ partial: { txid, vout } }));
        return await this.updateOutput(output.outputId, { basketId: undefined });
    }
    async processSyncChunk(args, chunk) {
        const user = (0, utilityHelpers_1.verifyTruthy)(await this.findUserByIdentityKey(args.identityKey));
        const ss = new entities_1.EntitySyncState((0, utilityHelpers_1.verifyOne)(await this.findSyncStates({
            partial: {
                storageIdentityKey: args.fromStorageIdentityKey,
                userId: user.userId
            }
        })));
        const r = await ss.processSyncChunk(this, args, chunk);
        return r;
    }
    /**
     * Handles storage changes when a valid MerklePath and mined block header are found for a ProvenTxReq txid.
     *
     * Performs the following storage updates (typically):
     * 1. Lookup the exising `ProvenTxReq` record for its rawTx
     * 2. Insert a new ProvenTx record using properties from `args` and rawTx, yielding a new provenTxId
     * 3. Update ProvenTxReq record with status 'completed' and new provenTxId value (and history of status changed)
     * 4. Unpack notify transactionIds from req and update each transaction's status to 'completed', provenTxId value.
     * 5. Update ProvenTxReq history again to record that transactions have been notified.
     * 6. Return results...
     *
     * Alterations of "typically" to handle:
     */
    async updateProvenTxReqWithNewProvenTx(args) {
        const req = await entities_1.EntityProvenTxReq.fromStorageId(this, args.provenTxReqId);
        let proven;
        if (req.provenTxId) {
            // Someone beat us to it, grab what we need for results...
            proven = new entities_1.EntityProvenTx((0, utilityHelpers_1.verifyOne)(await this.findProvenTxs({ partial: { txid: args.txid } })));
        }
        else {
            let isNew;
            ({ proven, isNew } = await this.transaction(async (trx) => {
                const { proven: api, isNew } = await this.findOrInsertProvenTx({
                    created_at: new Date(),
                    updated_at: new Date(),
                    provenTxId: 0,
                    txid: args.txid,
                    height: args.height,
                    index: args.index,
                    merklePath: args.merklePath,
                    rawTx: req.rawTx,
                    blockHash: args.blockHash,
                    merkleRoot: args.merkleRoot
                }, trx);
                proven = new entities_1.EntityProvenTx(api);
                if (isNew) {
                    req.status = 'completed';
                    req.provenTxId = proven.provenTxId;
                    await req.updateStorageDynamicProperties(this, trx);
                    // upate the transaction notifications outside of storage transaction....
                }
                return { proven, isNew };
            }));
            if (isNew) {
                const ids = req.notify.transactionIds || [];
                if (ids.length > 0) {
                    for (const id of ids) {
                        try {
                            await this.updateTransaction(id, {
                                provenTxId: proven.provenTxId,
                                status: 'completed'
                            });
                            req.addHistoryNote({ what: 'notifyTxOfProof', transactionId: id });
                        }
                        catch (eu) {
                            const { code, description } = WalletError_1.WalletError.fromUnknown(eu);
                            const { provenTxId } = proven;
                            req.addHistoryNote({ what: 'notifyTxOfProofError', id, provenTxId, code, description });
                        }
                    }
                    await req.updateStorageDynamicProperties(this);
                }
            }
        }
        const r = {
            status: req.status,
            history: req.apiHistory,
            provenTxId: proven.provenTxId
        };
        return r;
    }
    /**
     * For each spendable output in the 'default' basket of the authenticated user,
     * verify that the output script, satoshis, vout and txid match that of an output
     * still in the mempool of at least one service provider.
     *
     * @returns object with invalidSpendableOutputs array. A good result is an empty array.
     */
    async confirmSpendableOutputs() {
        const invalidSpendableOutputs = [];
        const users = await this.findUsers({ partial: {} });
        for (const { userId } of users) {
            const defaultBasket = (0, utilityHelpers_1.verifyOne)(await this.findOutputBaskets({ partial: { userId, name: 'default' } }));
            const where = {
                userId,
                basketId: defaultBasket.basketId,
                spendable: true
            };
            const outputs = await this.findOutputs({ partial: where });
            const services = this.getServices();
            for (let i = outputs.length - 1; i >= 0; i--) {
                const o = outputs[i];
                const oid = (0, utilityHelpers_1.verifyId)(o.outputId);
                if (o.spendable) {
                    let ok = false;
                    if (o.lockingScript && o.lockingScript.length > 0) {
                        const hash = services.hashOutputScript((0, utilityHelpers_noBuffer_1.asString)(o.lockingScript));
                        const r = await services.getUtxoStatus(hash, undefined, `${o.txid}.${o.vout}`);
                        if (r.isUtxo === true)
                            ok = true;
                    }
                    if (!ok)
                        invalidSpendableOutputs.push(o);
                }
            }
        }
        return { invalidSpendableOutputs };
    }
    async updateProvenTxReqDynamics(id, update, trx) {
        const partial = {};
        if (update['updated_at'])
            partial['updated_at'] = update['updated_at'];
        if (update['provenTxId'])
            partial['provenTxId'] = update['provenTxId'];
        if (update['status'])
            partial['status'] = update['status'];
        if (Number.isInteger(update['attempts']))
            partial['attempts'] = update['attempts'];
        if (update['notified'] !== undefined)
            partial['notified'] = update['notified'];
        if (update['batch'])
            partial['batch'] = update['batch'];
        if (update['history'])
            partial['history'] = update['history'];
        if (update['notify'])
            partial['notify'] = update['notify'];
        return await this.updateProvenTxReq(id, partial, trx);
    }
    async extendOutput(o, includeBasket = false, includeTags = false, trx) {
        const ox = o;
        if (includeBasket && ox.basketId)
            ox.basket = await this.findOutputBasketById(o.basketId, trx);
        if (includeTags) {
            ox.tags = await this.getTagsForOutputId(o.outputId);
        }
        return o;
    }
    async validateOutputScript(o, trx) {
        // without offset and length values return what we have (make no changes)
        if (!o.scriptLength || !o.scriptOffset || !o.txid)
            return;
        // if there is an outputScript and its length is the expected length return what we have.
        if (o.lockingScript && o.lockingScript.length === o.scriptLength)
            return;
        // outputScript is missing or has incorrect length...
        const script = await this.getRawTxOfKnownValidTransaction(o.txid, o.scriptOffset, o.scriptLength, trx);
        if (!script)
            return;
        o.lockingScript = script;
    }
}
exports.StorageProvider = StorageProvider;
function validateStorageFeeModel(v) {
    const r = {
        model: 'sat/kb',
        value: 1
    };
    if (typeof v === 'object') {
        if (v.model !== 'sat/kb')
            throw new WERR_errors_1.WERR_INVALID_PARAMETER('StorageFeeModel.model', `"sat/kb"`);
        if (typeof v.value === 'number') {
            r.value = v.value;
        }
    }
    return r;
}
//# sourceMappingURL=StorageProvider.js.map