"use strict";
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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createOfferAndSeller = createOfferAndSeller;
exports.createOfferWithCondition = createOfferWithCondition;
exports.createSellerAndOfferWithCondition = createSellerAndOfferWithCondition;
exports.createPremintedOfferAddToGroup = createPremintedOfferAddToGroup;
exports.createPremintedOfferWithCondition = createPremintedOfferWithCondition;
exports.createSellerAndPremintedOffer = createSellerAndPremintedOffer;
exports.createSellerAndPremintedOfferWithCondition = createSellerAndPremintedOfferWithCondition;
exports.commitToOfferAndRedeemVoucher = commitToOfferAndRedeemVoucher;
exports.commitToConditionalOfferAndRedeemVoucher = commitToConditionalOfferAndRedeemVoucher;
exports.createOfferCommitAndRedeem = createOfferCommitAndRedeem;
exports.raiseAndEscalateDispute = raiseAndEscalateDispute;
const common_1 = require("@bosonprotocol/common");
const interface_1 = require("./interface");
const storage_1 = require("../offers/storage");
const constants_1 = require("@ethersproject/constants");
const handler_1 = require("../accounts/handler");
const storeMetadataItems_1 = require("../metadata/storeMetadataItems");
const subgraph_1 = require("../offers/subgraph");
const handler_2 = require("../exchanges/handler");
const handler_3 = require("../erc20/handler");
const subgraph_2 = require("../accounts/subgraph");
function createOfferAndSeller(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
            abortEarly: false
        });
        common_1.utils.validation.createSellerArgsSchema.validateSync(args.sellerToCreate, {
            abortEarly: false
        });
        yield Promise.all([
            args.offerToCreate.metadataUri,
            args.sellerToCreate.metadataUri,
            args.sellerToCreate.contractUri
        ].map((metadataUri) => (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        })));
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.offerToCreate] }));
        const collectionSalt = yield (0, handler_1.findCollectionSalt)(args);
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCreateSellerAndOffer)(args.sellerToCreate, collectionSalt, args.offerToCreate)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function createOfferWithCondition(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
            abortEarly: false
        });
        yield (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: args.offerToCreate.metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        });
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.offerToCreate] }));
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCreateOfferWithCondition)(args.offerToCreate, args.condition)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function createSellerAndOfferWithCondition(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
            abortEarly: false
        });
        yield Promise.all([
            args.offerToCreate.metadataUri,
            args.sellerToCreate.metadataUri,
            args.sellerToCreate.contractUri
        ].map((metadataUri) => (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        })));
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.offerToCreate] }));
        const collectionSalt = yield (0, handler_1.findCollectionSalt)(args);
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCreateSellerAndOfferWithCondition)(args.sellerToCreate, collectionSalt, args.offerToCreate, args.condition)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function createPremintedOfferAddToGroup(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
            abortEarly: false
        });
        yield (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: args.offerToCreate.metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        });
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.offerToCreate] }));
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCreatePremintedOfferAddToGroup)(args.offerToCreate, args.premintParameters, args.groupId)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function createPremintedOfferWithCondition(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
            abortEarly: false
        });
        yield (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: args.offerToCreate.metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        });
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.offerToCreate] }));
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCreatePremintedOfferWithCondition)(args.offerToCreate, args.premintParameters, args.condition)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function createSellerAndPremintedOffer(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
            abortEarly: false
        });
        yield Promise.all([
            args.offerToCreate.metadataUri,
            args.sellerToCreate.metadataUri,
            args.sellerToCreate.contractUri
        ].map((metadataUri) => (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        })));
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.offerToCreate] }));
        const collectionSalt = yield (0, handler_1.findCollectionSalt)(args);
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCreateSellerAndPremintedOffer)(args.sellerToCreate, collectionSalt, args.offerToCreate, args.premintParameters)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function createSellerAndPremintedOfferWithCondition(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferArgsSchema.validateSync(args.offerToCreate, {
            abortEarly: false
        });
        yield Promise.all([
            args.offerToCreate.metadataUri,
            args.sellerToCreate.metadataUri,
            args.sellerToCreate.contractUri
        ].map((metadataUri) => (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        })));
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.offerToCreate] }));
        const collectionSalt = yield (0, handler_1.findCollectionSalt)(args);
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCreateSellerAndPremintedOfferWithCondition)(args.sellerToCreate, collectionSalt, args.offerToCreate, args.premintParameters, args.condition)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function commitToOfferAndRedeemVoucher(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const offer = yield (0, subgraph_1.getOfferById)(args.subgraphUrl, args.offerId);
        yield (0, handler_2.checkOfferIsCommittable)(args.offerId, offer);
        if (offer.creator !== common_1.OfferCreator.Seller) {
            throw new Error(`Offer with id ${args.offerId.toString()} is not seller initiated`);
        }
        if (offer.condition) {
            // keep compatibility with previous version
            if (args.returnTxInfo) {
                return commitToConditionalOfferAndRedeemVoucher(Object.assign(Object.assign({}, args), { returnTxInfo: true, tokenId: offer.condition.minTokenId }));
            }
            return commitToConditionalOfferAndRedeemVoucher(Object.assign(Object.assign({}, args), { returnTxInfo: false, tokenId: offer.condition.minTokenId }));
        }
        if (offer.exchangeToken.address !== constants_1.AddressZero) {
            const owner = yield args.web3Lib.getSignerAddress();
            yield (0, handler_3.ensureAllowance)({
                owner,
                spender: args.contractAddress,
                contractAddress: offer.exchangeToken.address,
                value: offer.price,
                web3Lib: args.web3Lib,
                returnTxInfo: args.returnTxInfo
            });
        }
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCommitToOfferAndRedeemVoucher)(args.offerId),
            value: offer.exchangeToken.address === constants_1.AddressZero ? offer.price : "0"
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function commitToConditionalOfferAndRedeemVoucher(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const offer = yield (0, subgraph_1.getOfferById)(args.subgraphUrl, args.offerId);
        yield (0, handler_2.checkOfferIsCommittable)(args.offerId, offer);
        if (offer.exchangeToken.address !== constants_1.AddressZero) {
            const owner = yield args.web3Lib.getSignerAddress();
            yield (0, handler_3.ensureAllowance)({
                owner,
                spender: args.contractAddress,
                contractAddress: offer.exchangeToken.address,
                value: offer.price,
                web3Lib: args.web3Lib,
                returnTxInfo: args.returnTxInfo
            });
        }
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeCommitToConditionalOfferAndRedeemVoucher)(args.offerId, args.tokenId),
            value: offer.exchangeToken.address === constants_1.AddressZero ? offer.price : "0"
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function createOfferCommitAndRedeem(args) {
    return __awaiter(this, void 0, void 0, function* () {
        common_1.utils.validation.createOfferAndCommitArgsSchema.validateSync(args.createOfferAndCommitArgs, {
            abortEarly: false
        });
        const { disputeResolverId, exchangeToken, price, sellerDeposit, creator } = args.createOfferAndCommitArgs;
        const disputeResolver = yield (0, subgraph_2.getDisputeResolverById)(args.subgraphUrl, disputeResolverId);
        if (!disputeResolver) {
            throw new Error(`Dispute resolver with id "${disputeResolverId}" does not exist`);
        }
        if (!disputeResolver.fees.some((fee) => fee.token.address.toLowerCase() === exchangeToken.toLowerCase())) {
            throw new Error(`Dispute resolver with id "${disputeResolverId}" does not support exchange token "${exchangeToken}"`);
        }
        if (yield (0, handler_2.isFullOfferVoided)(Object.assign(Object.assign({}, args), { fullOfferArgsUnsigned: args.createOfferAndCommitArgs }))) {
            throw new Error(`The offer has been voided`);
        }
        yield (0, storage_1.storeMetadataOnTheGraph)({
            metadataUriOrHash: args.createOfferAndCommitArgs.metadataUri,
            metadataStorage: args.metadataStorage,
            theGraphStorage: args.theGraphStorage
        });
        yield (0, storeMetadataItems_1.storeMetadataItems)(Object.assign(Object.assign({}, args), { createOffersArgs: [args.createOfferAndCommitArgs] }));
        const committerPayment = creator === common_1.OfferCreator.Buyer ? sellerDeposit : price;
        if (exchangeToken !== constants_1.AddressZero) {
            const owner = yield args.web3Lib.getSignerAddress();
            yield (0, handler_3.ensureAllowance)({
                owner,
                spender: args.contractAddress,
                contractAddress: exchangeToken,
                value: committerPayment,
                web3Lib: args.web3Lib,
                returnTxInfo: args.returnTxInfo
            });
        }
        const transactionRequest = Object.assign(Object.assign({}, args.txRequest), { to: args.contractAddress, data: (0, interface_1.encodeCreateOfferCommitAndRedeem)(args.createOfferAndCommitArgs), value: exchangeToken === constants_1.AddressZero ? committerPayment : "0" });
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
function raiseAndEscalateDispute(args) {
    return __awaiter(this, void 0, void 0, function* () {
        const transactionRequest = {
            to: args.contractAddress,
            data: (0, interface_1.encodeRaiseAndEscalateDispute)(args.exchangeId)
        };
        if (args.returnTxInfo) {
            return transactionRequest;
        }
        else {
            return args.web3Lib.sendTransaction(transactionRequest);
        }
    });
}
//# sourceMappingURL=handler.js.map