import { __awaiter, __generator } from "tslib";
import assert from "assert";
function makeKey(tx) {
    return JSON.stringify(Object.entries(tx).map(function (_a) {
        var key = _a[0], value = _a[1];
        return [key, (value || "").toString()];
    }));
}
export default (function (config, signer, emit) {
    if (emit === void 0) { emit = function () { return null; }; }
    assert(signer.provider, "signer requires a provider, use signer.connect(provider)");
    var _a = config.confirmations, confirmations = _a === void 0 ? 3 : _a;
    var requests = new Map();
    var submissions = new Map();
    var mined = new Map();
    function request(unsignedTx) {
        // this no longer calls signer.populateTransaction, to allow metamask to fill in missing details instead
        // use overrides if you want to manually fill in other tx details, including the overrides.customData field.
        var populated = unsignedTx;
        var key = makeKey(populated);
        assert(!requests.has(key), "Transaction already in progress");
        requests.set(key, populated);
        return key;
    }
    function processRequest(key) {
        return __awaiter(this, void 0, void 0, function () {
            var request, sent, err_1;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        request = requests.get(key);
                        assert(request, "invalid request");
                        // always delete request, it should only be submitted once
                        requests.delete(key);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, signer.sendTransaction(request)];
                    case 2:
                        sent = _a.sent();
                        submissions.set(key, sent.hash);
                        emit("submitted", key, sent.hash);
                        return [3 /*break*/, 4];
                    case 3:
                        err_1 = _a.sent();
                        emit("error", key, err_1);
                        return [3 /*break*/, 4];
                    case 4: return [2 /*return*/];
                }
            });
        });
    }
    function processSubmission(key) {
        return __awaiter(this, void 0, void 0, function () {
            var hash, receipt;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        hash = submissions.get(key);
                        assert(hash, "invalid submission");
                        assert(signer.provider, "signer requires a provider, use signer.connect(provider)");
                        return [4 /*yield*/, signer.provider.getTransactionReceipt(hash).catch(function () { return undefined; })];
                    case 1:
                        receipt = _a.sent();
                        if (receipt == null)
                            return [2 /*return*/];
                        if (receipt.confirmations < confirmations)
                            return [2 /*return*/];
                        submissions.delete(key);
                        mined.set(key, receipt);
                        emit("mined", key, receipt);
                        return [2 /*return*/];
                }
            });
        });
    }
    function isMined(key) {
        return Promise.resolve(mined.get(key));
    }
    function update() {
        return __awaiter(this, void 0, void 0, function () {
            var _i, _a, key, _b, _c, key;
            return __generator(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        _i = 0, _a = Array.from(requests.keys());
                        _d.label = 1;
                    case 1:
                        if (!(_i < _a.length)) return [3 /*break*/, 4];
                        key = _a[_i];
                        return [4 /*yield*/, processRequest(key)];
                    case 2:
                        _d.sent();
                        _d.label = 3;
                    case 3:
                        _i++;
                        return [3 /*break*/, 1];
                    case 4:
                        _b = 0, _c = Array.from(submissions.keys());
                        _d.label = 5;
                    case 5:
                        if (!(_b < _c.length)) return [3 /*break*/, 8];
                        key = _c[_b];
                        return [4 /*yield*/, processSubmission(key)];
                    case 6:
                        _d.sent();
                        _d.label = 7;
                    case 7:
                        _b++;
                        return [3 /*break*/, 5];
                    case 8: return [2 /*return*/];
                }
            });
        });
    }
    return {
        request: request,
        isMined: isMined,
        update: update,
    };
});
//# sourceMappingURL=transactionManager.js.map