"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());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const bn_js_1 = __importDefault(require("bn.js"));
const utilities_1 = require("./utilities");
const balance_reader_1 = require("../src/balance_reader");
const MockContract = artifacts.require("MockContract");
const BatchExchange = artifacts.require("BatchExchange");
contract("BatchExchange utils", (accounts) => __awaiter(void 0, void 0, void 0, function* () {
    describe("getBalanceState()", () => __awaiter(void 0, void 0, void 0, function* () {
        it("retrieves balance as in storage", () => __awaiter(void 0, void 0, void 0, function* () {
            const erc20 = yield MockContract.new();
            yield erc20.givenAnyReturnBool(true);
            const batchExchange = yield BatchExchange.new(1, erc20.address);
            yield utilities_1.closeAuction(batchExchange);
            // amount is hex 100 to catch possible zero padding issues in the function
            yield batchExchange.deposit(erc20.address, 0x100);
            yield utilities_1.applyBalances(accounts[0], batchExchange, [erc20.address]);
            const balance = yield balance_reader_1.getBalanceState(accounts[0], erc20.address, batchExchange.address, web3);
            assert.equal(balance.toNumber(), 0x100);
        }));
    }));
    describe("getWithdrawableAmount()", () => __awaiter(void 0, void 0, void 0, function* () {
        const startingAmount = new bn_js_1.default("100");
        it("returns zero for future withdraw request", () => __awaiter(void 0, void 0, void 0, function* () {
            const erc20 = yield MockContract.new();
            yield erc20.givenAnyReturnBool(true);
            const batchExchange = yield BatchExchange.new(1, erc20.address);
            yield utilities_1.closeAuction(batchExchange);
            yield batchExchange.deposit(erc20.address, startingAmount);
            yield utilities_1.applyBalances(accounts[0], batchExchange, [erc20.address]);
            const futureBatchId = Math.pow(2, 32) - 1;
            yield batchExchange.requestFutureWithdraw(erc20.address, startingAmount, futureBatchId);
            const withdrawableAmount = yield balance_reader_1.getWithdrawableAmount(accounts[0], erc20.address, batchExchange, web3);
            assert.equal(withdrawableAmount.toString(), "0");
        }));
        it("returns amount when withdraw was already requested", () => __awaiter(void 0, void 0, void 0, function* () {
            const erc20 = yield MockContract.new();
            yield erc20.givenAnyReturnBool(true);
            const batchExchange = yield BatchExchange.new(1, erc20.address);
            yield utilities_1.closeAuction(batchExchange);
            yield batchExchange.deposit(erc20.address, startingAmount);
            yield utilities_1.applyBalances(accounts[0], batchExchange, [erc20.address]);
            yield batchExchange.requestWithdraw(erc20.address, startingAmount);
            yield utilities_1.closeAuction(batchExchange);
            const withdrawableAmount = yield balance_reader_1.getWithdrawableAmount(accounts[0], erc20.address, batchExchange, web3);
            assert.equal(withdrawableAmount.toString(), startingAmount.toString());
            const transcript = yield batchExchange.withdraw(accounts[0], erc20.address);
            assert.equal(withdrawableAmount.toString(), transcript.logs[0].args.amount.toString());
        }));
        it("returns entire balance when withdraw of more than available was requested", () => __awaiter(void 0, void 0, void 0, function* () {
            const erc20 = yield MockContract.new();
            yield erc20.givenAnyReturnBool(true);
            const batchExchange = yield BatchExchange.new(1, erc20.address);
            yield utilities_1.closeAuction(batchExchange);
            yield batchExchange.deposit(erc20.address, startingAmount);
            yield utilities_1.applyBalances(accounts[0], batchExchange, [erc20.address]);
            yield batchExchange.requestWithdraw(erc20.address, startingAmount.addn(1));
            yield utilities_1.closeAuction(batchExchange);
            const withdrawableAmount = yield balance_reader_1.getWithdrawableAmount(accounts[0], erc20.address, batchExchange, web3);
            assert.equal(withdrawableAmount.toString(), startingAmount.toString());
            const transcript = yield batchExchange.withdraw(accounts[0], erc20.address);
            assert.equal(withdrawableAmount.toString(), transcript.logs[0].args.amount.toString());
        }));
        it("ignores deposits if funds are not yet available", () => __awaiter(void 0, void 0, void 0, function* () {
            const erc20 = yield MockContract.new();
            yield erc20.givenAnyReturnBool(true);
            const batchExchange = yield BatchExchange.new(1, erc20.address);
            yield utilities_1.closeAuction(batchExchange);
            yield batchExchange.deposit(erc20.address, startingAmount);
            yield utilities_1.applyBalances(accounts[0], batchExchange, [erc20.address]);
            const newAmount = new bn_js_1.default("200");
            const fullBalance = newAmount.add(startingAmount);
            yield batchExchange.requestWithdraw(erc20.address, fullBalance);
            yield utilities_1.closeAuction(batchExchange);
            yield batchExchange.deposit(erc20.address, newAmount);
            const withdrawableAmount = yield balance_reader_1.getWithdrawableAmount(accounts[0], erc20.address, batchExchange, web3);
            assert.equal(withdrawableAmount.toString(), startingAmount.toString());
            const transcript = yield batchExchange.withdraw(accounts[0], erc20.address);
            assert.equal(withdrawableAmount.toString(), transcript.logs[0].args.amount.toString());
        }));
        it("considers deposits if funds are available", () => __awaiter(void 0, void 0, void 0, function* () {
            const erc20 = yield MockContract.new();
            yield erc20.givenAnyReturnBool(true);
            const batchExchange = yield BatchExchange.new(1, erc20.address);
            yield utilities_1.closeAuction(batchExchange);
            yield batchExchange.deposit(erc20.address, startingAmount);
            yield utilities_1.applyBalances(accounts[0], batchExchange, [erc20.address]);
            const newAmount = new bn_js_1.default("200");
            const fullBalance = newAmount.add(startingAmount);
            yield batchExchange.requestWithdraw(erc20.address, fullBalance);
            yield batchExchange.deposit(erc20.address, newAmount);
            yield utilities_1.closeAuction(batchExchange);
            const withdrawableAmount = yield balance_reader_1.getWithdrawableAmount(accounts[0], erc20.address, batchExchange, web3);
            assert.equal(withdrawableAmount.toString(), fullBalance.toString());
            const transcript = yield batchExchange.withdraw(accounts[0], erc20.address);
            assert.equal(withdrawableAmount.toString(), transcript.logs[0].args.amount.toString());
        }));
        // untested case: lastCreditBatchId != 0
    }));
}));
