"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.utilityOverflow = exports.marginalTrade = exports.stableXExample = exports.smallExample = exports.tooSmallBuyAmountTrade = exports.tooSmallSellAmountTrade = exports.exampleOrderWithUnlimitedAmount = exports.shortRingBetterTrade = exports.largeRing30 = exports.basicRingTrade = exports.biggieSmallTrade = exports.advancedTrade = exports.basicTrade = void 0;
const bn_js_1 = __importDefault(require("bn.js"));
const math_1 = require("../math");
const generate_1 = require("./generate");
__exportStar(require("./generate"), exports);
const ZERO = new bn_js_1.default(0);
exports.basicTrade = generate_1.generateTestCase({
    name: "Basic Trade",
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(math_1.toETH(20)).add(math_1.ERROR_EPSILON),
            buyAmount: math_1.toETH(10),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(10),
            buyAmount: math_1.feeSubtracted(math_1.toETH(20)).sub(math_1.ERROR_EPSILON),
            user: 1,
        },
    ],
    solutions: [
        {
            name: "Full Solution",
            prices: [1, 2].map(math_1.toETH),
            buyVolumes: [math_1.toETH(10), math_1.feeSubtracted(math_1.toETH(20))],
        },
        {
            name: "Partial Solution",
            prices: [1, 2].map(math_1.toETH),
            buyVolumes: [math_1.toETH(9), math_1.feeSubtracted(math_1.toETH(18))],
        },
    ],
});
exports.advancedTrade = generate_1.generateTestCase({
    name: "Advanced Trade",
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(math_1.toETH(20)).add(math_1.ERROR_EPSILON),
            buyAmount: math_1.toETH(10),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(10),
            buyAmount: math_1.feeSubtracted(math_1.toETH(20)).sub(math_1.ERROR_EPSILON),
            user: 1,
        },
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(math_1.toETH(20)).add(math_1.ERROR_EPSILON),
            buyAmount: math_1.toETH(10),
            user: 2,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(10),
            buyAmount: math_1.feeSubtracted(math_1.toETH(20)).sub(math_1.ERROR_EPSILON),
            user: 3,
        },
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(math_1.toETH(20)).add(math_1.ERROR_EPSILON),
            buyAmount: math_1.toETH(10),
            user: 4,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(10),
            buyAmount: math_1.feeSubtracted(math_1.toETH(20)).sub(math_1.ERROR_EPSILON),
            user: 5,
        },
    ],
    solutions: [
        {
            name: "Match 1 Pair",
            prices: [1, 2].map(math_1.toETH),
            buyVolumes: [math_1.toETH(10), math_1.feeSubtracted(math_1.toETH(20)), ZERO, ZERO, ZERO, ZERO],
        },
        {
            name: "Match 2 Pairs",
            prices: [1, 2].map(math_1.toETH),
            buyVolumes: [
                math_1.toETH(10),
                math_1.feeSubtracted(math_1.toETH(20)),
                math_1.toETH(10),
                math_1.feeSubtracted(math_1.toETH(20)),
                ZERO,
                ZERO,
            ],
        },
        {
            name: "Match 3 Pairs",
            prices: [1, 2].map(math_1.toETH),
            buyVolumes: [
                math_1.toETH(10),
                math_1.feeSubtracted(math_1.toETH(20)),
                math_1.toETH(10),
                math_1.feeSubtracted(math_1.toETH(20)),
                math_1.toETH(10),
                math_1.feeSubtracted(math_1.toETH(20)),
            ],
        },
    ],
});
exports.biggieSmallTrade = generate_1.generateTestCase({
    name: "Biggie Small",
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.toETH(185),
            buyAmount: math_1.toETH(1),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(1000),
            buyAmount: math_1.toETH(184000),
            user: 1,
        },
    ],
    solutions: [
        {
            name: "Max Fulfillment",
            prices: [math_1.toETH(1), math_1.feeAdded(math_1.toETH(184))],
            buyVolumes: [1, 184].map(math_1.toETH),
        },
    ],
});
exports.basicRingTrade = generate_1.generateTestCase({
    name: "Basic Ring",
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.toETH(1),
            buyAmount: math_1.toETH(0.99),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 2,
            sellAmount: math_1.toETH(1),
            buyAmount: math_1.toETH(0.99),
            user: 1,
        },
        {
            sellToken: 2,
            buyToken: 0,
            sellAmount: math_1.toETH(1),
            buyAmount: math_1.toETH(0.99),
            user: 2,
        },
    ],
    solutions: [
        {
            name: "Ring Around the Rosie",
            prices: [1, 1, 1].map(math_1.toETH),
            buyVolumes: [
                math_1.feeSubtracted(math_1.toETH(1), 1),
                math_1.feeSubtracted(math_1.toETH(1), 2),
                math_1.feeSubtracted(math_1.toETH(1), 3),
            ],
        },
    ],
});
const n = 30;
exports.largeRing30 = generate_1.generateTestCase({
    name: "Longest Ring Trade",
    orders: Array.from(Array(n).keys())
        .map((i) => ({
        sellToken: i % n,
        buyToken: (i + 1) % n,
        sellAmount: math_1.toETH(1),
        buyAmount: math_1.toETH(0.99),
        user: i % 2,
    }))
        .concat(Array.from(Array(n).keys()).map((i) => ({
        sellToken: i % n,
        buyToken: (i + 1) % n,
        sellAmount: math_1.toETH(1),
        buyAmount: math_1.toETH(0.99),
        user: 2 + (i % 2),
    }))),
    solutions: [
        {
            name: "Solution filling ~90% of the available volume",
            prices: [
                new bn_js_1.default("1000000000000000000"),
                new bn_js_1.default("999000000079933840"),
                new bn_js_1.default("998001000078845135"),
                new bn_js_1.default("997002999140535506"),
                new bn_js_1.default("996005996035392883"),
                new bn_js_1.default("995009990083786472"),
                new bn_js_1.default("994014980130495716"),
                new bn_js_1.default("993020965086898658"),
                new bn_js_1.default("992027944164247585"),
                new bn_js_1.default("991035916140546385"),
                new bn_js_1.default("990044880290088817"),
                new bn_js_1.default("989054835391299816"),
                new bn_js_1.default("988065780510318410"),
                new bn_js_1.default("987077714823955022"),
                new bn_js_1.default("986090637068828536"),
                new bn_js_1.default("985104546427501883"),
                new bn_js_1.default("984119441847563266"),
                new bn_js_1.default("983135322401663687"),
                new bn_js_1.default("982152187132755565"),
                new bn_js_1.default("981170034910294548"),
                new bn_js_1.default("980188864899078269"),
                new bn_js_1.default("979208676045659066"),
                new bn_js_1.default("978229467305820489"),
                new bn_js_1.default("977251237858427284"),
                new bn_js_1.default("976273986614832057"),
                new bn_js_1.default("975297712672815304"),
                new bn_js_1.default("974322414953157214"),
                new bn_js_1.default("973348092529574952"),
                new bn_js_1.default("982063340537758779"),
                new bn_js_1.default("990991090090097194"),
            ],
            buyVolumes: Array(30)
                .fill(new bn_js_1.default(0))
                .concat([
                new bn_js_1.default("899999909927988434"),
                new bn_js_1.default("899999909928898147"),
                new bn_js_1.default("899999909873138748"),
                new bn_js_1.default("899999909968923181"),
                new bn_js_1.default("899999909928736570"),
                new bn_js_1.default("899999909895423467"),
                new bn_js_1.default("899999909952944811"),
                new bn_js_1.default("899999909914445655"),
                new bn_js_1.default("899999909986676388"),
                new bn_js_1.default("899999909926967303"),
                new bn_js_1.default("899999909943800566"),
                new bn_js_1.default("899999909985327246"),
                new bn_js_1.default("899999909899485749"),
                new bn_js_1.default("899999909936269665"),
                new bn_js_1.default("899999909940159650"),
                new bn_js_1.default("899999909970806338"),
                new bn_js_1.default("899999909974515710"),
                new bn_js_1.default("899999909925496645"),
                new bn_js_1.default("899999909957902274"),
                new bn_js_1.default("899999909936146659"),
                new bn_js_1.default("899999909925595398"),
                new bn_js_1.default("899999909984286761"),
                new bn_js_1.default("899999909965948230"),
                new bn_js_1.default("899999909971236827"),
                new bn_js_1.default("899999909930081941"),
                new bn_js_1.default("899999909936534371"),
                new bn_js_1.default("899999909944513216"),
                new bn_js_1.default("891120914814366045"),
                new bn_js_1.default("882209793797187023"),
                new bn_js_1.default("873387783197991000"),
            ]),
        },
        {
            name: "Full solution to large ring trade",
            prices: [
                new bn_js_1.default("1000000000000000000"),
                new bn_js_1.default("999000000080932527"),
                new bn_js_1.default("998001000163952351"),
                new bn_js_1.default("997002999153048099"),
                new bn_js_1.default("996005996120621788"),
                new bn_js_1.default("995009990197501127"),
                new bn_js_1.default("994014980201782351"),
                new bn_js_1.default("993020965255715327"),
                new bn_js_1.default("992027944249700231"),
                new bn_js_1.default("991035916321243854"),
                new bn_js_1.default("990044880335294951"),
                new bn_js_1.default("989054835476903275"),
                new bn_js_1.default("988065780622280566"),
                new bn_js_1.default("987077714922662489"),
                new bn_js_1.default("986090637193173669"),
                new bn_js_1.default("985104546487832659"),
                new bn_js_1.default("984119441958561945"),
                new bn_js_1.default("983135322499977058"),
                new bn_js_1.default("982152187194035945"),
                new bn_js_1.default("981170035069292740"),
                new bn_js_1.default("980188864985054793"),
                new bn_js_1.default("979208676167400239"),
                new bn_js_1.default("978229467438980960"),
                new bn_js_1.default("977251237967802060"),
                new bn_js_1.default("976273986723981212"),
                new bn_js_1.default("975297712793135196"),
                new bn_js_1.default("974322415061859070"),
                new bn_js_1.default("973348092626909555"),
                new bn_js_1.default("982063340537758779"),
                new bn_js_1.default("990991090090097095"),
            ],
            buyVolumes: [
                new bn_js_1.default("999999900018987366"),
                new bn_js_1.default("999999899935720167"),
                new bn_js_1.default("999999899946492752"),
                new bn_js_1.default("999999899979899439"),
                new bn_js_1.default("999999899906533389"),
                new bn_js_1.default("999999899912087908"),
                new bn_js_1.default("999999899877713252"),
                new bn_js_1.default("999999899918800176"),
                new bn_js_1.default("999999899902864002"),
                new bn_js_1.default("999999899973191776"),
                new bn_js_1.default("999999899951005325"),
                new bn_js_1.default("999999899970382379"),
                new bn_js_1.default("999999899888317721"),
                new bn_js_1.default("999999899903089341"),
                new bn_js_1.default("999999899972267613"),
                new bn_js_1.default("999999899954772667"),
                new bn_js_1.default("999999899971684198"),
                new bn_js_1.default("999999899954824426"),
                new bn_js_1.default("999999899891175087"),
                new bn_js_1.default("999999899941337511"),
                new bn_js_1.default("999999899893002057"),
                new bn_js_1.default("999999899946416798"),
                new bn_js_1.default("999999899950243776"),
                new bn_js_1.default("999999899956239066"),
                new bn_js_1.default("999999899898945833"),
                new bn_js_1.default("999999899917915929"),
                new bn_js_1.default("999999899938348141"),
                new bn_js_1.default("990134349892753397"),
                new bn_js_1.default("980233104317120013"),
                new bn_js_1.default("970430870317033000"),
            ].concat(Array(30).fill(new bn_js_1.default(0))),
        },
    ],
});
exports.shortRingBetterTrade = generate_1.generateTestCase({
    orders: [
        // ring trade orders
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.toETH(1),
            buyAmount: math_1.toETH(0.99),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 2,
            sellAmount: math_1.toETH(1),
            buyAmount: math_1.toETH(0.99),
            user: 1,
        },
        {
            sellToken: 2,
            buyToken: 0,
            sellAmount: math_1.toETH(1),
            buyAmount: math_1.toETH(0.99),
            user: 2,
        },
        // biggie small orders
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.toETH(185),
            buyAmount: math_1.toETH(1),
            user: 3,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(1000),
            buyAmount: math_1.toETH(184000),
            user: 4,
        },
    ],
    solutions: [
        {
            name: "Ring Trade Solution",
            prices: [1, 1, 1].map(math_1.toETH),
            buyVolumes: [
                math_1.feeSubtracted(math_1.toETH(1), 1),
                math_1.feeSubtracted(math_1.toETH(1), 2),
                math_1.feeSubtracted(math_1.toETH(1), 3),
                ZERO,
                ZERO,
            ],
        },
        {
            name: "Biggie Small Trade",
            prices: [math_1.toETH(1), math_1.feeAdded(math_1.toETH(184)), ZERO],
            buyVolumes: [ZERO, ZERO, ZERO, math_1.toETH(1), math_1.toETH(184)],
        },
    ],
});
const maxUint128 = new bn_js_1.default(2).pow(new bn_js_1.default(128)).sub(new bn_js_1.default(1));
exports.exampleOrderWithUnlimitedAmount = generate_1.generateTestCase({
    deposits: [
        { amount: math_1.feeAdded(math_1.toETH(10)), token: 0, user: 0 },
        { amount: math_1.feeAdded(math_1.toETH(10)), token: 1, user: 1 },
    ],
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: maxUint128,
            buyAmount: math_1.feeSubtracted(maxUint128.div(new bn_js_1.default(4))),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(10),
            buyAmount: math_1.feeSubtracted(math_1.toETH(5)),
            user: 1,
        },
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(maxUint128.div(new bn_js_1.default(2))),
            buyAmount: maxUint128,
            user: 0,
        },
    ],
    solutions: [
        {
            prices: [1, 0.5].map(math_1.toETH),
            buyVolumes: [ZERO, math_1.feeSubtracted(math_1.toETH(5)), math_1.toETH(10)],
        },
        {
            prices: [1, 1].map(math_1.toETH),
            buyVolumes: [math_1.toETH(10), math_1.feeSubtracted(math_1.toETH(10)), ZERO],
        },
    ],
}, false, false);
const fiveThousand = new bn_js_1.default("5000");
const tenThousand = new bn_js_1.default("10000");
exports.tooSmallSellAmountTrade = generate_1.generateTestCase({
    deposits: [
        { amount: math_1.feeAdded(tenThousand), token: 0, user: 0 },
        { amount: math_1.feeAdded(tenThousand), token: 1, user: 1 },
    ],
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(tenThousand),
            buyAmount: fiveThousand,
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.feeAdded(tenThousand),
            buyAmount: fiveThousand,
            user: 1,
        },
    ],
    solutions: [
        {
            name: "Small sell amount",
            prices: [1, 0.9].map(math_1.toETH),
            buyVolumes: [tenThousand, tenThousand],
        },
    ],
}, false, true);
exports.tooSmallBuyAmountTrade = generate_1.generateTestCase({
    deposits: [
        { amount: math_1.feeAdded(tenThousand), token: 0, user: 0 },
        { amount: math_1.feeAdded(tenThousand), token: 1, user: 1 },
    ],
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(tenThousand),
            buyAmount: fiveThousand,
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.feeAdded(tenThousand),
            buyAmount: fiveThousand,
            user: 1,
        },
    ],
    solutions: [
        {
            name: "Small buy amounts",
            prices: [1, 1].map(math_1.toETH),
            buyVolumes: [10000, 9990].map((val) => new bn_js_1.default(val)),
        },
    ],
}, false, true);
const fiftyThousand = new bn_js_1.default("50000");
const hundredThousand = new bn_js_1.default("100000");
exports.smallExample = generate_1.generateTestCase({
    deposits: [
        { amount: math_1.feeAdded(hundredThousand), token: 0, user: 0 },
        { amount: new bn_js_1.default(190), token: 1, user: 1 },
        { amount: new bn_js_1.default(9), token: 0, user: 1 },
        { amount: math_1.feeAdded(hundredThousand), token: 1, user: 2 },
    ],
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(hundredThousand),
            buyAmount: fiftyThousand,
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.feeAdded(hundredThousand),
            buyAmount: fiftyThousand,
            user: 1,
        },
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(hundredThousand),
            buyAmount: fiftyThousand,
            user: 1,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.feeAdded(hundredThousand),
            buyAmount: fiftyThousand,
            user: 2,
        },
    ],
    solutions: [
        {
            name: "Small Solution",
            prices: [1, 1].map(math_1.toETH),
            buyVolumes: [100000, 99900, 99810, 99711].map((val) => new bn_js_1.default(val)),
        },
    ],
});
exports.stableXExample = generate_1.generateTestCase({
    deposits: [
        { amount: math_1.toETH(3000), token: 0, user: 0 },
        { amount: math_1.toETH(3000), token: 1, user: 0 },
    ],
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.toETH(2000),
            buyAmount: math_1.toETH(999),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(999),
            buyAmount: math_1.toETH(1996),
            user: 1,
        },
    ],
    solutions: [
        {
            name: "Naive Solver",
            prices: [math_1.toETH(1), new bn_js_1.default("1999998997996995993")],
            buyVolumes: [math_1.toETH(999), new bn_js_1.default("1996000999999999998010")],
        },
    ],
});
exports.marginalTrade = generate_1.generateTestCase({
    name: "Marginal Trade",
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(math_1.toETH(20)).add(math_1.ERROR_EPSILON),
            buyAmount: math_1.toETH(10),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(10),
            buyAmount: math_1.feeSubtracted(math_1.toETH(20)).sub(math_1.ERROR_EPSILON),
            user: 1,
        },
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.feeAdded(math_1.toETH(200000)).add(math_1.ERROR_EPSILON),
            buyAmount: math_1.toETH(100000),
            user: 2,
        },
        {
            sellToken: 1,
            buyToken: 0,
            sellAmount: math_1.toETH(100000),
            buyAmount: math_1.feeSubtracted(math_1.toETH(200000)).sub(math_1.ERROR_EPSILON),
            user: 3,
        },
    ],
    solutions: [
        {
            name: "First Solution",
            prices: [1, 2].map(math_1.toETH),
            buyVolumes: [math_1.toETH(10), math_1.feeSubtracted(math_1.toETH(20)), ZERO, ZERO],
        },
        {
            name: "Marginally Solution",
            prices: [1, 2].map(math_1.toETH),
            buyVolumes: [ZERO, ZERO, math_1.toETH(100000), math_1.feeSubtracted(math_1.toETH(200000))],
        },
    ],
});
exports.utilityOverflow = generate_1.generateTestCase({
    deposits: [
        { amount: math_1.toETH(10), token: 0, user: 0 },
        { amount: math_1.toETH(1), token: 1, user: 1 },
        { amount: math_1.toETH(100), token: 2, user: 2 },
    ],
    orders: [
        {
            sellToken: 0,
            buyToken: 1,
            sellAmount: math_1.toETH(10),
            buyAmount: new bn_js_1.default("10000000000000000"),
            user: 0,
        },
        {
            sellToken: 1,
            buyToken: 2,
            sellAmount: math_1.toETH(1),
            buyAmount: new bn_js_1.default("1000"),
            user: 1,
        },
        {
            sellToken: 2,
            buyToken: 1,
            sellAmount: math_1.toETH(100),
            buyAmount: math_1.toETH(1),
            user: 2,
        },
    ],
    solutions: [
        {
            name: "Utility Overflow",
            prices: [
                "1000000000000000000",
                "998999900119977150048",
                "10000000000198528574",
            ].map((val) => new bn_js_1.default(val)),
            buyVolumes: [
                "1998999800099984",
                "99800080039994614733",
                "998000900199892164",
            ].map((val) => new bn_js_1.default(val)),
        },
    ],
});
