From ac3a3e1d31854de538beba4c59f6821d31a79352 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Tue, 14 Oct 2025 03:50:07 +0000 Subject: [PATCH 1/7] stabull constants and abi --- src/common/abis/index.ts | 2 + src/common/abis/stabull.ts | 54 +++++++++++++++++ src/router/stabull/constants.ts | 102 ++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 src/common/abis/stabull.ts create mode 100644 src/router/stabull/constants.ts diff --git a/src/common/abis/index.ts b/src/common/abis/index.ts index dde1052a..e48a527c 100644 --- a/src/common/abis/index.ts +++ b/src/common/abis/index.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ +import { StabullAbi } from "./stabull"; import { RouteProcessorAbi } from "./rp"; import { DeployerAbi } from "./deployer"; import { OrderbookAbi } from "./orderbook"; @@ -8,6 +9,7 @@ import { ArbitrumNodeInterfaceAbi } from "./arbitrum"; /** Keeps all necesdsary ABIs for rain solver app */ export namespace ABI { + export import Stabull = StabullAbi; export import Deployer = DeployerAbi; export import Orderbook = OrderbookAbi; export import Multicall3 = Multicall3Abi; diff --git a/src/common/abis/stabull.ts b/src/common/abis/stabull.ts new file mode 100644 index 00000000..247586c9 --- /dev/null +++ b/src/common/abis/stabull.ts @@ -0,0 +1,54 @@ +/** Keeps Stabull protocol related ABIs */ +export namespace StabullAbi { + /** Stabull primary contracts */ + export namespace Primary { + /** Stabull Router contract ABI */ + export const Router = [ + { + inputs: [], + name: "factory", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_quoteCurrency", type: "address" }, + { internalType: "address", name: "_origin", type: "address" }, + { internalType: "address", name: "_target", type: "address" }, + { internalType: "uint256", name: "_originAmount", type: "uint256" }, + { internalType: "uint256", name: "_minTargetAmount", type: "uint256" }, + { internalType: "uint256", name: "_deadline", type: "uint256" }, + ], + name: "originSwap", + outputs: [{ internalType: "uint256", name: "targetAmount_", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_quoteCurrency", type: "address" }, + { internalType: "address", name: "_origin", type: "address" }, + { internalType: "address", name: "_target", type: "address" }, + { internalType: "uint256", name: "_originAmount", type: "uint256" }, + ], + name: "viewOriginSwap", + outputs: [{ internalType: "uint256", name: "targetAmount_", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_quoteCurrency", type: "address" }, + { internalType: "address", name: "_origin", type: "address" }, + { internalType: "address", name: "_target", type: "address" }, + { internalType: "uint256", name: "_targetAmount", type: "uint256" }, + ], + name: "viewTargetSwap", + outputs: [{ internalType: "uint256", name: "originAmount_", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + ] as const; + } +} diff --git a/src/router/stabull/constants.ts b/src/router/stabull/constants.ts new file mode 100644 index 00000000..87fb9654 --- /dev/null +++ b/src/router/stabull/constants.ts @@ -0,0 +1,102 @@ +import { ChainId } from "sushi"; + +/** Keeps Stabull protocol contract addresses */ +export namespace StabullConstants { + /** Supported chains by the Stabull protocol */ + export const SupportedChains = [ChainId.ETHEREUM, ChainId.POLYGON, ChainId.BASE] as const; + + /** Determines if the given chain is supported by the Stabull protocol */ + export function isChainSupported(chainId: number): chainId is (typeof SupportedChains)[number] { + return SupportedChains.includes(chainId as any); + } + + /** Stabull protocol router addresses per chain */ + export const Routers = { + [ChainId.ETHEREUM]: "0x871af97122d08890193e8d6465015f6d9e2889b2", + [ChainId.POLYGON]: "0x0c1f53e7b5a770f4c0d4bef139f752eeb08de88d", + [ChainId.BASE]: "0x4b82759d385e905c85d1fcf7811ed33b738965a0", + } as const; + + /** Stabull protocol supported tokens per chain */ + export const Tokens = { + [ChainId.ETHEREUM]: { + EURS: "0xdb25f211ab05b1c97d595516f45794528a807ad8", + GYEN: "0xc08512927d12348f6620a698105e1baac6ecd911", + NZDS: "0xda446fad08277b4d2591536f204e018f32b6831c", + TRYB: "0x2c537e5624e4af88a7ae4060c022609376c8d0eb", + USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + }, + [ChainId.POLYGON]: { + BRZ: "0x4ed141110f6eeeaba9a1df36d8c26f684d2475dc", + COPM: "0x12050c705152931cfee3dd56c52fb09dea816c23", + DAI: "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", + EURS: "0xe111178a87a3bff0c8d18decba5798827539ae99", + NZDS: "0xfbbe4b730e1e77d02dc40fedf9438e2802eab3b5", + OFD: "0x9cfb3b1b217b41c4e748774368099dd8dd7e89a1", + PAXG: "0x553d3d295e0f695b9228246232edf400ed3560b5", + PHPC: "0x87a25dc121db52369f4a9971f664ae5e372cf69a", + TRYB: "0x4fb71290ac171e1d144f7221d882becac7196eb5", + USDC: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359", + USDT: "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", + XSGD: "0xdc3326e71d45186f113a2f448984ca0e8d201995", + ZCHF: "0x02567e4b14b25549331fcee2b56c647a8bab16fd", + }, + [ChainId.BASE]: { + BRZ: "0xe9185ee218cae427af7b9764a011bb89fea761b4", + EURC: "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + MXNe: "0x269cae7dc59803e5c596c95756faeebb6030e0af", + TRYB: "0xfb8718a69aed7726afb3f04d2bd4bfde1bdcb294", + ZARP: "0xb755506531786c8ac63b756bab1ac387bacb0c04", + ZCHF: "0xd4dd9e2f021bb459d5a5f6c24c12fe09c5d45553", + OFD: "0x7479791022eb1030bbc3b09f6575c5db4ddc0b90", + USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + }, + } as const; + + /** List of Stabull protocol supported tokens per chain */ + export const TokenList = { + [ChainId.ETHEREUM]: new Set(Object.values(Tokens[ChainId.ETHEREUM])) as Set, + [ChainId.POLYGON]: new Set(Object.values(Tokens[ChainId.POLYGON])) as Set, + [ChainId.BASE]: new Set(Object.values(Tokens[ChainId.BASE])) as Set, + } as const; + + /** Stabull protocol quote currencies per chain */ + export const QuoteCurrency = { + [ChainId.ETHEREUM]: Tokens[ChainId.ETHEREUM].USDC, + [ChainId.POLYGON]: Tokens[ChainId.POLYGON].USDC, + [ChainId.BASE]: Tokens[ChainId.BASE].USDC, + } as const; + + /** Stabull protocol deployed pools (token pair pools) per chain */ + export const Pools = { + [ChainId.ETHEREUM]: { + "GYEN-USDC": "0x01e4013c478d7f02112c3cf178f2771c842edbd0", + "EURS-USDC": "0x865040f92ac6cca1b9683c03d843799d8e6d1282", + "NZDS-USDC": "0xe37d763c7c4cdd9a8f085f7db70139a0843529f3", + "TRYB-USDC": "0xc1a195fdb17da5771d470a232545550a7d264809", + }, + [ChainId.POLYGON]: { + "BRZ-USDC": "0xce0abd182d2cf5844f2a0cb52cfcc55d4ff4fcba", + "COPM-USDC": "0x9caa728e1935c8b332dc4e9ec9d57666fc9e7ff4", + "DAI-USDC": "0xa52508b1822ca9261b33213b233694f846abd0ed", + "EURS-USDC": "0xf80b3a8977d34a443a836a380b2fce69a1a4e819", + "NZDS-USDC": "0xdcb7efaca996fe2985138bf31b647efcd1d0901a", + "OFD-USDC": "0x5cc08ce8fd0f66d83cb39300b268602514e2926b", + "PAXG-USDC": "0xbefc1cbf4a8c4a8af76d2e35287f11a3ac4fca29", + "PHPC-USDC": "0x1233003461f654cf1c0d7db19e753badef05a87f", + "TRYB-USDC": "0x55bdf7f0223e8b1d509141a8d852dd86b3553d59", + "USDT-USDC": "0x3d4436ba3ae7e0e6361c83ab940ea779cd598206", + "XSGD-USDC": "0x509aacb7746166252ecb0d62bfba097cc9731e20", + "ZCHF-USDC": "0xd840d0361c36709e62c13ec42253dc0c3e326c1d", + }, + [ChainId.BASE]: { + "BRZ-USDC": "0x8a908ae045e611307755a91f4d6ecd04ed31eb1b", + "EURC-USDC": "0x2a645d27efe5c8f5afc63856d2509ea20f81a0b2", + "MXNE-USDC": "0xc642e57d55853baa61e7f7c4894894235f221f82", + "TRYB-USDC": "0x1f039c1dfe7eb98c49d11dbf74b476853127e963", + "ZARP-USDC": "0x63129f8948225fe08b9c921186bafa27e6710833", + "ZCHF-USDC": "0xc77c42baa1bdf2708c5ef8cfca3533b3e09b058f", + "OFD-USDC": "0x27cd7e6837e2a043ba760a8f67f73b8f0b7de8f3", + }, + } as const; +} From a385183cb4573b2282040ca3a56ba03c56632afb Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Tue, 14 Oct 2025 04:16:40 +0000 Subject: [PATCH 2/7] stabull arb contract config --- config.env.yaml | 2 ++ config.example.yaml | 4 ++++ src/config/validators.ts | 12 ++++++++++++ src/config/yaml.test.ts | 2 ++ src/config/yaml.ts | 2 ++ src/state/contracts.test.ts | 30 ++++++++++++++++++++++++++++++ src/state/contracts.ts | 20 ++++++++++++++++++++ 7 files changed, 72 insertions(+) diff --git a/config.env.yaml b/config.env.yaml index 1adabea1..536e67b2 100644 --- a/config.env.yaml +++ b/config.env.yaml @@ -10,11 +10,13 @@ contracts: sushiArbAddress: $ARB_ADDRESS genericArbAddress: $GENERIC_ARB_ADDRESS balancerArbAddress: $BALANCER_ARB_ADDRESS + stabullArbAddress: $STABULL_ARB_ADDRESS dispair: $DISPAIR v5: sushiArbAddress: $ARB_ADDRESS_V5 genericArbAddress: $GENERIC_ARB_ADDRESS_V5 balancerArbAddress: $BALANCER_ARB_ADDRESS_V5 + stabullArbAddress: $STABULL_ARB_ADDRESS_V5 dispair: $DISPAIR_V5 liquidityProviders: $LIQUIDITY_PROVIDERS route: $ROUTE diff --git a/config.example.yaml b/config.example.yaml index 3e4cceec..ff849e4d 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -46,6 +46,8 @@ contracts: genericArbAddress: "0x1234...5678" # Balancer arb v4 contract address balancerArbAddress: "0x1234...5678" + # Stabull arb v4 contract address + stabullArbAddress: "0x1234...5678" # Dispair v4 contract address dispair: "0x1234...5678" v5: @@ -55,6 +57,8 @@ contracts: genericArbAddress: "0x1234...5678" # Balancer arb v5 contract address balancerArbAddress: "0x1234...5678" + # Stabull arb v5 contract address + stabullArbAddress: "0x1234...5678" # Dispair v5 contract address dispair: "0x1234...5678" diff --git a/src/config/validators.ts b/src/config/validators.ts index bb29979d..b46ff85b 100644 --- a/src/config/validators.ts +++ b/src/config/validators.ts @@ -486,6 +486,11 @@ export namespace Validator { "balancerArbAddress v4", true, ); + const stabullArbAddressV4 = resolveAddress( + input?.contracts?.v4?.stabullArbAddress, + "stabullArbAddress v4", + true, + ); const dispairV5 = resolveAddress(input?.contracts?.v5?.dispair, "dispair v5", true); const sushiArbAddressV5 = resolveAddress( input?.contracts?.v5?.sushiArbAddress, @@ -502,6 +507,11 @@ export namespace Validator { "balancerArbAddress v5", true, ); + const stabullArbAddressV5 = resolveAddress( + input?.contracts?.v5?.stabullArbAddress, + "stabullArbAddress v5", + true, + ); const contracts: AppOptionsContracts = {}; if (dispairV4 || sushiArbAddressV4 || genericArbAddressV4 || balancerArbAddressV4) { contracts.v4 = { @@ -509,6 +519,7 @@ export namespace Validator { dispair: dispairV4 as `0x${string}` | undefined, genericArb: genericArbAddressV4 as `0x${string}` | undefined, balancerArb: balancerArbAddressV4 as `0x${string}` | undefined, + stabullArb: stabullArbAddressV4 as `0x${string}` | undefined, }; } if (dispairV5 || sushiArbAddressV5 || genericArbAddressV5 || balancerArbAddressV5) { @@ -517,6 +528,7 @@ export namespace Validator { dispair: dispairV5 as `0x${string}` | undefined, genericArb: genericArbAddressV5 as `0x${string}` | undefined, balancerArb: balancerArbAddressV5 as `0x${string}` | undefined, + stabullArb: stabullArbAddressV5 as `0x${string}` | undefined, }; } return contracts; diff --git a/src/config/yaml.test.ts b/src/config/yaml.test.ts index b17ed44f..dca76554 100644 --- a/src/config/yaml.test.ts +++ b/src/config/yaml.test.ts @@ -23,6 +23,7 @@ contracts: sushiArbAddress: "0x1111111111111111111111111111111111111111" balancerArbAddress: "0x3333333333333333333333333333333333333333" dispair: "0x2222222222222222222222222222222222222222" + stabullArbAddress: "0x4444444444444444444444444444444444444444" liquidityProviders: - lp1 - lp2 @@ -90,6 +91,7 @@ orderbookTradeTypes: balancerArb: "0x3333333333333333333333333333333333333333", dispair: "0x2222222222222222222222222222222222222222", genericArb: undefined, + stabullArb: "0x4444444444444444444444444444444444444444", }, }, liquidityProviders: ["lp1", "lp2"], diff --git a/src/config/yaml.ts b/src/config/yaml.ts index fdca15b6..8bc8cbae 100644 --- a/src/config/yaml.ts +++ b/src/config/yaml.ts @@ -34,12 +34,14 @@ export type AppOptionsContracts = { dispair?: `0x${string}`; genericArb?: `0x${string}`; balancerArb?: `0x${string}`; + stabullArb?: `0x${string}`; }; v5?: { sushiArb?: `0x${string}`; dispair?: `0x${string}`; genericArb?: `0x${string}`; balancerArb?: `0x${string}`; + stabullArb?: `0x${string}`; }; }; diff --git a/src/state/contracts.test.ts b/src/state/contracts.test.ts index 5a575f4b..a2b2e9be 100644 --- a/src/state/contracts.test.ts +++ b/src/state/contracts.test.ts @@ -25,12 +25,14 @@ describe("SolverContracts.fromAppOptions", () => { sushiArb: "0xv4sushiArb" as `0x${string}`, genericArb: "0xv4genericArb" as `0x${string}`, balancerArb: "0xv4balancerArb" as `0x${string}`, + stabullArb: "0xv4stabullArb" as `0x${string}`, }, v5: { dispair: "0xv5dispair" as `0x${string}`, sushiArb: "0xv5sushiArb" as `0x${string}`, genericArb: "0xv5genericArb" as `0x${string}`, balancerArb: "0xv5balancerArb" as `0x${string}`, + stabullArb: "0xv5stabullArb" as `0x${string}`, }, }, } as AppOptions; @@ -51,6 +53,7 @@ describe("SolverContracts.fromAppOptions", () => { sushiArb: "0xv4sushiArb", genericArb: "0xv4genericArb", balancerArb: "0xv4balancerArb", + stabullArb: "0xv4stabullArb", dispair: { deployer: "0xv4dispair", interpreter: "0xv4interpreter", @@ -61,6 +64,7 @@ describe("SolverContracts.fromAppOptions", () => { sushiArb: "0xv5sushiArb", genericArb: "0xv5genericArb", balancerArb: "0xv5balancerArb", + stabullArb: "0xv5stabullArb", dispair: { deployer: "0xv5dispair", interpreter: "0xv5interpreter", @@ -110,6 +114,7 @@ describe("SolverContracts.fromAppOptions", () => { sushiArb: "0xv5sushiArb", genericArb: "0xv5genericArb", balancerArb: "0xv5balancerArb", + stabullArb: "0xv5stabullArb", dispair: { deployer: "0xv5dispair", interpreter: "0xv5interpreter", @@ -137,6 +142,7 @@ describe("SolverContracts.fromAppOptions", () => { sushiArb: "0xv4sushiArb", genericArb: "0xv4genericArb", balancerArb: "0xv4balancerArb", + stabullArb: "0xv4stabullArb", dispair: { deployer: "0xv4dispair", interpreter: "0xv4interpreter", @@ -195,6 +201,7 @@ describe("SolverContracts.fromAppOptions", () => { sushiArb: "0xv4sushiArb", genericArb: "0xv4genericArb", balancerArb: "0xv4balancerArb", + stabullArb: "0xv4stabullArb", dispair: { deployer: "0xv4dispair", interpreter: "0xv4interpreter", @@ -319,6 +326,7 @@ describe("resolveVersionContracts", () => { sushiArb: "0xsushiArbAddress" as `0x${string}`, genericArb: "0xgenericArbAddress" as `0x${string}`, balancerArb: "0xbalancerArbAddress" as `0x${string}`, + stabullArb: "0xstabullArbAddress" as `0x${string}`, }; // Mock successful contract calls @@ -337,6 +345,7 @@ describe("resolveVersionContracts", () => { sushiArb: "0xsushiArbAddress", genericArb: "0xgenericArbAddress", balancerArb: "0xbalancerArbAddress", + stabullArb: "0xstabullArbAddress", }); expect(mockClient.readContract).toHaveBeenCalledTimes(2); @@ -484,6 +493,7 @@ describe("versionAddressGetter", () => { sushiArb: "0xsushiArbAddress" as `0x${string}`, genericArb: "0xgenericArbAddress" as `0x${string}`, balancerArb: "0xbalancerArbAddress" as `0x${string}`, + stabullArb: "0xstabullArbAddress" as `0x${string}`, }; // Create mock order @@ -585,6 +595,26 @@ describe("versionAddressGetter", () => { expect(result).toBeUndefined(); }); + it("should return stabullArb for Stabull tradeType when available", () => { + const result = versionAddressGetter(mockContracts, mockOrder, TradeType.Stabull); + + expect(result).toEqual({ + dispair: mockContracts.dispair, + destination: "0xstabullArbAddress", + }); + }); + + it("should return undefined for Stabull tradeType when stabullArb is not available", () => { + const contractsWithoutStabull = { + ...mockContracts, + stabullArb: undefined, + }; + + const result = versionAddressGetter(contractsWithoutStabull, mockOrder, TradeType.Stabull); + + expect(result).toBeUndefined(); + }); + it("should return genericArb for InterOrderbook tradeType when available", () => { const result = versionAddressGetter(mockContracts, mockOrder, TradeType.InterOrderbook); diff --git a/src/state/contracts.ts b/src/state/contracts.ts index 2464b60f..1ce85e3a 100644 --- a/src/state/contracts.ts +++ b/src/state/contracts.ts @@ -15,12 +15,14 @@ export type SolverContracts = { sushiArb?: `0x${string}`; genericArb?: `0x${string}`; balancerArb?: `0x${string}`; + stabullArb?: `0x${string}`; dispair: Dispair; }; v5?: { sushiArb?: `0x${string}`; genericArb?: `0x${string}`; balancerArb?: `0x${string}`; + stabullArb?: `0x${string}`; dispair: Dispair; }; @@ -101,6 +103,9 @@ export async function resolveVersionContracts( if (addresses.balancerArb) { result.balancerArb = addresses.balancerArb; } + if (addresses.stabullArb) { + result.stabullArb = addresses.stabullArb; + } return result; } @@ -131,6 +136,12 @@ export function versionAddressGetter< destination: contracts.balancerArb, }; } + if (contracts.stabullArb) { + return { + dispair: contracts.dispair, + destination: contracts.stabullArb, + }; + } return undefined; } case TradeType.RouteProcessor: { @@ -151,6 +162,15 @@ export function versionAddressGetter< } return undefined; } + case TradeType.Stabull: { + if (contracts.stabullArb) { + return { + dispair: contracts.dispair, + destination: contracts.stabullArb, + }; + } + return undefined; + } case TradeType.InterOrderbook: { if (contracts.genericArb) { return { From a09b165ccc796dcb7d9de30f8351dab5304c54a2 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Wed, 15 Oct 2025 15:28:50 +0000 Subject: [PATCH 3/7] update --- src/core/modes/router/simulate.ts | 24 +- src/core/types.ts | 1 + src/router/error.ts | 11 +- src/router/router.test.ts | 113 +++- src/router/router.ts | 91 ++- src/router/stabull/error.ts | 36 ++ src/router/stabull/index.test.ts | 544 ++++++++++++++++++ src/router/stabull/index.ts | 269 +++++++++ src/router/types.ts | 16 +- src/state/index.test.ts | 8 +- src/state/index.ts | 2 + ...StabullRouterOrderBookV5ArbOrderTaker.json | 1 + test/e2e/data.js | 25 + test/e2e/e2e.test.js | 335 +++++++++++ test/utils.js | 12 + 15 files changed, 1430 insertions(+), 58 deletions(-) create mode 100644 src/router/stabull/error.ts create mode 100644 src/router/stabull/index.test.ts create mode 100644 src/router/stabull/index.ts create mode 100644 test/abis/StabullRouterOrderBookV5ArbOrderTaker.json diff --git a/src/core/modes/router/simulate.ts b/src/core/modes/router/simulate.ts index f53cb8d6..e346dede 100644 --- a/src/core/modes/router/simulate.ts +++ b/src/core/modes/router/simulate.ts @@ -41,7 +41,7 @@ export type SimulateRouterTradeArgs = { /** Arguments for preparing router trade type parameters required for simulation and building tx object */ export type RouterTradePreparedParams = { - type: TradeType.Router | TradeType.Balancer | TradeType.RouteProcessor; + type: TradeType.Router | TradeType.Balancer | TradeType.RouteProcessor | TradeType.Stabull; rawtx: RawTransaction; price: bigint; minimumExpected: bigint; @@ -118,15 +118,21 @@ export class RouterTradeSimulator extends TradeSimulatorBase { takeOrdersConfigStruct, } = tradeParamsResult.value; - // determine trade type based on router type + // determine trade type based on route type let type = TradeType.Router; - if (routeType === RouterType.Sushi) { - type = TradeType.RouteProcessor; - } else if (routeType === RouterType.Balancer) { - type = TradeType.Balancer; - } else { - // unreachable path - type = TradeType.Router; + switch (routeType) { + case RouterType.Sushi: { + type = TradeType.RouteProcessor; + break; + } + case RouterType.Balancer: { + type = TradeType.Balancer; + break; + } + case RouterType.Stabull: { + type = TradeType.Stabull; + break; + } } this.spanAttributes["amountOut"] = formatUnits(quote.amountOut, toToken.decimals); diff --git a/src/core/types.ts b/src/core/types.ts index a1ffa7b5..85325b35 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -30,6 +30,7 @@ export enum TradeType { InterOrderbook = "interOrderbook", Balancer = "balancer", Router = "router", + Stabull = "stabull", } /** Base type for process order results containing shared fields */ diff --git a/src/router/error.ts b/src/router/error.ts index 80a4de3d..8bd1e4ce 100644 --- a/src/router/error.ts +++ b/src/router/error.ts @@ -1,9 +1,11 @@ import { RainSolverBaseError } from "../error"; import { SushiRouterError } from "./sushi/error"; import { BalancerRouterError } from "./balancer/error"; +import { StabullRouterError } from "./stabull/error"; -// re-export all error types from sushi and balancer +// re-export all error types from sushi, balancer and stabull export * from "./sushi/error"; +export * from "./stabull/error"; export * from "./balancer/error"; /** Enumerates the possible error types that can occur within the RainSolverRouter functionalities */ @@ -28,11 +30,14 @@ export class RainSolverRouterError extends RainSolverBaseError { typ?: RainSolverRouterErrorType; sushiError?: SushiRouterError; balancerError?: BalancerRouterError; + stabullError?: StabullRouterError; + constructor( message: string, type: RainSolverRouterErrorType, sushiError?: SushiRouterError, balancerError?: BalancerRouterError, + stabullError?: StabullRouterError, ) { const msgs = [message]; if (sushiError) { @@ -41,10 +46,14 @@ export class RainSolverRouterError extends RainSolverBaseError { if (balancerError) { msgs.push(`BalancerRouterError: ${balancerError.message}`); } + if (stabullError) { + msgs.push(`StabullRouterError: ${stabullError.message}`); + } super(msgs.join("\n")); this.typ = type; this.sushiError = sushiError; this.balancerError = balancerError; + this.stabullError = stabullError; this.name = "RainSolverRouterError"; } } diff --git a/src/router/router.test.ts b/src/router/router.test.ts index 83c6c463..1f83037a 100644 --- a/src/router/router.test.ts +++ b/src/router/router.test.ts @@ -15,7 +15,10 @@ import { SushiRouterErrorType, BalancerRouterErrorType, RainSolverRouterErrorType, + StabullRouterErrorType, + StabullRouterError, } from "./error"; +import { StabullRouter } from "./stabull"; describe("RainSolverRouter", () => { const chainId = 1; @@ -37,6 +40,7 @@ describe("RainSolverRouter", () => { let router: RainSolverRouter; let mockSushiRouter: SushiRouter; let mockBalancerRouter: BalancerRouter; + let mockStabullRouter: StabullRouter; let mockClient: PublicClient; beforeEach(() => { @@ -44,16 +48,24 @@ describe("RainSolverRouter", () => { mockClient = createMockPublicClient(); mockSushiRouter = createMockSushiRouter(); mockBalancerRouter = createMockBalancerRouter(); - router = new RainSolverRouter(chainId, mockClient, mockSushiRouter, mockBalancerRouter); + mockStabullRouter = createMockStabullRouter(); + router = new RainSolverRouter( + chainId, + mockClient, + mockSushiRouter, + mockBalancerRouter, + mockStabullRouter, + ); }); describe("test create static method", () => { - it("should create router with both sushi and balancer when both succeed", async () => { + it("should create router with sushi, balancer and stabull when both succeed", async () => { const mockConfig: RainSolverRouterConfig = { chainId, client: mockClient, sushiRouterConfig: { sushiRouteProcessor4Address: "0xsushi" as `0x${string}` }, balancerRouterConfig: { balancerRouterAddress: "0xbalancer" as `0x${string}` }, + stabullRouter: true, }; const sushiCreateSpy = vi.spyOn(SushiRouter, "create"); @@ -62,6 +74,9 @@ describe("RainSolverRouter", () => { const balancerCreateSpy = vi.spyOn(BalancerRouter, "create"); balancerCreateSpy.mockResolvedValue(Result.ok(mockBalancerRouter)); + const stabullCreateSpy = vi.spyOn(StabullRouter, "create"); + stabullCreateSpy.mockResolvedValue(Result.ok(mockStabullRouter)); + const result = await RainSolverRouter.create(mockConfig); assert(result.isOk()); @@ -78,9 +93,11 @@ describe("RainSolverRouter", () => { mockClient, "0xbalancer" as `0x${string}`, ); + expect(stabullCreateSpy).toHaveBeenCalledWith(chainId, mockClient); sushiCreateSpy.mockRestore(); balancerCreateSpy.mockRestore(); + stabullCreateSpy.mockRestore(); }); it("should create router with only balancer when sushi fails", async () => { @@ -168,9 +185,10 @@ describe("RainSolverRouter", () => { gasPrice, }; - it("should call both sushi and balancer getMarketPrice and return highest price", async () => { + it("should call both sushi, balancer and stabull getMarketPrice and return highest price", async () => { const sushiResult = Result.ok({ price: "2500.5" }) as any; const balancerResult = Result.ok({ price: "3000.0" }) as any; + const stabullResult = Result.ok({ price: "1500.0" }) as any; const sushiSpy = vi.spyOn(mockSushiRouter, "getMarketPrice"); sushiSpy.mockResolvedValue(sushiResult); @@ -178,15 +196,20 @@ describe("RainSolverRouter", () => { const balancerSpy = vi.spyOn(mockBalancerRouter, "getMarketPrice"); balancerSpy.mockResolvedValue(balancerResult); + const stabullSpy = vi.spyOn(mockStabullRouter, "getMarketPrice"); + stabullSpy.mockResolvedValue(stabullResult); + const result = await router.getMarketPrice(mockParams); assert(result.isOk()); expect(result.value.price).toBe("3000.0"); expect(sushiSpy).toHaveBeenCalledWith(mockParams); expect(balancerSpy).toHaveBeenCalledWith(mockParams); + expect(stabullSpy).toHaveBeenCalledWith({ ...mockParams, sushiRouter: router.sushi }); sushiSpy.mockRestore(); balancerSpy.mockRestore(); + stabullSpy.mockRestore(); }); it("should return sushi result when balancer fails", async () => { @@ -237,13 +260,16 @@ describe("RainSolverRouter", () => { balancerSpy.mockRestore(); }); - it("should return error when both fail", async () => { + it("should return error when all fail", async () => { const sushiResult = Result.err( new SushiRouterError("sushi error", SushiRouterErrorType.NoRouteFound), ) as any; const balancerResult = Result.err( new BalancerRouterError("balancer error", BalancerRouterErrorType.NoRouteFound), ) as any; + const stabullResult = Result.err( + new StabullRouterError("stabull error", StabullRouterErrorType.NoRouteFound), + ) as any; const sushiSpy = vi.spyOn(mockSushiRouter, "getMarketPrice"); sushiSpy.mockResolvedValue(sushiResult); @@ -251,6 +277,9 @@ describe("RainSolverRouter", () => { const balancerSpy = vi.spyOn(mockBalancerRouter, "getMarketPrice"); balancerSpy.mockResolvedValue(balancerResult); + const stabullSpy = vi.spyOn(mockStabullRouter, "getMarketPrice"); + stabullSpy.mockResolvedValue(stabullResult); + const result = await router.getMarketPrice(mockParams); assert(result.isErr()); @@ -258,9 +287,11 @@ describe("RainSolverRouter", () => { expect(result.error.typ).toBe(RainSolverRouterErrorType.NoRouteFound); expect(sushiSpy).toHaveBeenCalledWith(mockParams); expect(balancerSpy).toHaveBeenCalledWith(mockParams); + expect(stabullSpy).toHaveBeenCalledWith({ ...mockParams, sushiRouter: router.sushi }); sushiSpy.mockRestore(); balancerSpy.mockRestore(); + stabullSpy.mockRestore(); }); it("should sort results by price correctly", async () => { @@ -335,7 +366,7 @@ describe("RainSolverRouter", () => { gasPrice, }; - it("should call both sushi and balancer tryQuote and return highest amountOut", async () => { + it("should call sushi, balancer and stabull tryQuote and return highest amountOut", async () => { const sushiResult = Result.ok({ type: RouterType.Sushi, status: RouteStatus.Success, @@ -348,6 +379,12 @@ describe("RainSolverRouter", () => { price: 3000n * ONE18, amountOut: 3000000000n, }) as any; + const stabullResult = Result.ok({ + type: RouterType.Stabull as const, + status: RouteStatus.Success, + price: 3000n * ONE18, + amountOut: 1500000000n, + }) as any; const sushiSpy = vi.spyOn(mockSushiRouter, "tryQuote"); sushiSpy.mockResolvedValue(sushiResult); @@ -355,6 +392,9 @@ describe("RainSolverRouter", () => { const balancerSpy = vi.spyOn(mockBalancerRouter, "tryQuote"); balancerSpy.mockResolvedValue(balancerResult); + const stabullSpy = vi.spyOn(mockStabullRouter, "tryQuote"); + stabullSpy.mockResolvedValue(stabullResult); + const result = await router.tryQuote(mockParams); assert(result.isOk()); @@ -362,9 +402,11 @@ describe("RainSolverRouter", () => { expect(result.value.type).toBe(RouterType.Balancer); expect(sushiSpy).toHaveBeenCalledWith(mockParams); expect(balancerSpy).toHaveBeenCalledWith(mockParams); + expect(stabullSpy).toHaveBeenCalledWith(mockParams); sushiSpy.mockRestore(); balancerSpy.mockRestore(); + stabullSpy.mockRestore(); }); it("should return sushi result when balancer fails", async () => { @@ -491,7 +533,7 @@ describe("RainSolverRouter", () => { gasPrice, }; - it("should call both sushi and balancer findBestRoute and return highest amountOut", async () => { + it("should call sushi, balancer and stabull findBestRoute and return highest amountOut", async () => { const sushiResult = Result.ok({ type: RouterType.Sushi, status: RouteStatus.Success, @@ -504,6 +546,12 @@ describe("RainSolverRouter", () => { price: 3000n * ONE18, amountOut: 3000000000n, }) as any; + const stabullResult = Result.ok({ + type: RouterType.Stabull as const, + status: RouteStatus.Success, + price: 3000n * ONE18, + amountOut: 1500000000n, + }) as any; const sushiSpy = vi.spyOn(mockSushiRouter, "findBestRoute"); sushiSpy.mockResolvedValue(sushiResult); @@ -511,6 +559,9 @@ describe("RainSolverRouter", () => { const balancerSpy = vi.spyOn(mockBalancerRouter, "findBestRoute"); balancerSpy.mockResolvedValue(balancerResult); + const stabullSpy = vi.spyOn(mockStabullRouter, "findBestRoute"); + stabullSpy.mockResolvedValue(stabullResult); + const result = await router.findBestRoute(mockParams); assert(result.isOk()); @@ -518,18 +569,23 @@ describe("RainSolverRouter", () => { expect(result.value.amountOut).toBe(3000000000n); expect(sushiSpy).toHaveBeenCalledWith(mockParams); expect(balancerSpy).toHaveBeenCalledWith(mockParams); + expect(stabullSpy).toHaveBeenCalledWith(mockParams); sushiSpy.mockRestore(); balancerSpy.mockRestore(); + stabullSpy.mockRestore(); }); - it("should return error when both fail", async () => { + it("should return error when all fail", async () => { const sushiResult = Result.err( new SushiRouterError("sushi error", SushiRouterErrorType.NoRouteFound), ) as any; const balancerResult = Result.err( new BalancerRouterError("balancer error", BalancerRouterErrorType.NoRouteFound), ) as any; + const stabullResult = Result.err( + new StabullRouterError("stabull error", StabullRouterErrorType.NoRouteFound), + ) as any; const sushiSpy = vi.spyOn(mockSushiRouter, "findBestRoute"); sushiSpy.mockResolvedValue(sushiResult); @@ -537,6 +593,9 @@ describe("RainSolverRouter", () => { const balancerSpy = vi.spyOn(mockBalancerRouter, "findBestRoute"); balancerSpy.mockResolvedValue(balancerResult); + const stabullSpy = vi.spyOn(mockStabullRouter, "findBestRoute"); + stabullSpy.mockResolvedValue(stabullResult); + const result = await router.findBestRoute(mockParams); assert(result.isErr()); @@ -544,9 +603,11 @@ describe("RainSolverRouter", () => { expect(result.error.typ).toBe(RainSolverRouterErrorType.NoRouteFound); expect(sushiSpy).toHaveBeenCalledWith(mockParams); expect(balancerSpy).toHaveBeenCalledWith(mockParams); + expect(stabullSpy).toHaveBeenCalledWith(mockParams); sushiSpy.mockRestore(); balancerSpy.mockRestore(); + stabullSpy.mockRestore(); }); it("should sort results by amountOut descending", async () => { @@ -659,7 +720,7 @@ describe("RainSolverRouter", () => { isPartial: false, } as any; - it("should call both sushi and balancer getTradeParams and return highest amountOut", async () => { + it("should call sushi, balancer and stabull getTradeParams and return highest amountOut", async () => { const sushiResult = Result.ok({ type: RouterType.Sushi, quote: { @@ -682,6 +743,17 @@ describe("RainSolverRouter", () => { routeVisual: [], takeOrdersConfigStruct: {} as any, }) as any; + const stabullResult = Result.ok({ + type: RouterType.Stabull, + quote: { + type: RouterType.Stabull as const, + status: RouteStatus.Success, + price: 3000n * ONE18, + amountOut: 1500000000n, + }, + routeVisual: [], + takeOrdersConfigStruct: {} as any, + }) as any; const sushiSpy = vi.spyOn(mockSushiRouter, "getTradeParams"); sushiSpy.mockResolvedValue(sushiResult); @@ -689,6 +761,9 @@ describe("RainSolverRouter", () => { const balancerSpy = vi.spyOn(mockBalancerRouter, "getTradeParams"); balancerSpy.mockResolvedValue(balancerResult); + const stabullSpy = vi.spyOn(mockStabullRouter, "getTradeParams"); + stabullSpy.mockResolvedValue(stabullResult); + const result = await router.getTradeParams(mockArgs); assert(result.isOk()); @@ -696,18 +771,23 @@ describe("RainSolverRouter", () => { expect(result.value.quote.amountOut).toBe(3000000000n); expect(sushiSpy).toHaveBeenCalledWith(mockArgs); expect(balancerSpy).toHaveBeenCalledWith(mockArgs); + expect(stabullSpy).toHaveBeenCalledWith(mockArgs); sushiSpy.mockRestore(); balancerSpy.mockRestore(); + stabullSpy.mockRestore(); }); - it("should return error when both fail", async () => { + it("should return error when all fail", async () => { const sushiResult = Result.err( new SushiRouterError("sushi error", SushiRouterErrorType.FetchFailed), ) as any; const balancerResult = Result.err( new BalancerRouterError("balancer error", BalancerRouterErrorType.FetchFailed), ) as any; + const stabullResult = Result.err( + new StabullRouterError("stabull error", StabullRouterErrorType.FetchFailed), + ) as any; const sushiSpy = vi.spyOn(mockSushiRouter, "getTradeParams"); sushiSpy.mockResolvedValue(sushiResult); @@ -715,6 +795,9 @@ describe("RainSolverRouter", () => { const balancerSpy = vi.spyOn(mockBalancerRouter, "getTradeParams"); balancerSpy.mockResolvedValue(balancerResult); + const stabullSpy = vi.spyOn(mockStabullRouter, "getTradeParams"); + stabullSpy.mockResolvedValue(stabullResult); + const result = await router.getTradeParams(mockArgs); assert(result.isErr()); @@ -722,9 +805,11 @@ describe("RainSolverRouter", () => { expect(result.error.typ).toBe(RainSolverRouterErrorType.FetchFailed); expect(sushiSpy).toHaveBeenCalledWith(mockArgs); expect(balancerSpy).toHaveBeenCalledWith(mockArgs); + expect(stabullSpy).toHaveBeenCalledWith(mockArgs); sushiSpy.mockRestore(); balancerSpy.mockRestore(); + stabullSpy.mockRestore(); }); it("should return error when both fail", async () => { @@ -933,3 +1018,13 @@ function createMockBalancerRouter(): BalancerRouter { function createMockPublicClient(): PublicClient { return {} as any; } + +function createMockStabullRouter(): StabullRouter { + return { + getMarketPrice: vi.fn(), + tryQuote: vi.fn(), + findBestRoute: vi.fn(), + getTradeParams: vi.fn(), + getLiquidityProvidersList: vi.fn(), + } as any; +} diff --git a/src/router/router.ts b/src/router/router.ts index ef6d2e23..96f00b69 100644 --- a/src/router/router.ts +++ b/src/router/router.ts @@ -20,6 +20,8 @@ import { BalancerRouterErrorType, RainSolverRouterErrorType, } from "./error"; +import { StabullRouter } from "./stabull"; +import { StabullRouterError, StabullRouterErrorType } from "./stabull/error"; export type RainSolverRouterConfig = { /** The chain id of the operating chain */ @@ -38,6 +40,8 @@ export type RainSolverRouterConfig = { /** The address of the Balancer BatchRouter contract */ balancerRouterAddress: `0x${string}`; }; + /** Optional configuration for enabling the Stabull router */ + stabullRouter?: boolean; }; /** @@ -46,19 +50,21 @@ export type RainSolverRouterConfig = { * as managing runtime cache for routes. */ export class RainSolverRouter extends RainSolverRouterBase { - /** The protocol version of the RainSolverRouter */ readonly sushi: SushiRouter | undefined; readonly balancer: BalancerRouter | undefined; + readonly stabull: StabullRouter | undefined; constructor( chainId: number, client: PublicClient, sushiRouter?: SushiRouter, balancerRouter?: BalancerRouter, + stabullRouter?: StabullRouter, ) { super(chainId, client); this.sushi = sushiRouter; this.balancer = balancerRouter; + this.stabull = stabullRouter; } /** @@ -69,7 +75,7 @@ export class RainSolverRouter extends RainSolverRouterBase { static async create( config: RainSolverRouterConfig, ): Promise> { - const { chainId, client, balancerRouterConfig, sushiRouterConfig } = config; + const { chainId, client, balancerRouterConfig, sushiRouterConfig, stabullRouter } = config; const sushiResult: Result = sushiRouterConfig ? await SushiRouter.create( chainId, @@ -95,34 +101,34 @@ export class RainSolverRouter extends RainSolverRouterBase { BalancerRouterErrorType.UnsupportedChain, ), ); - if (sushiResult.isErr() && balancerResult.isErr()) { + const stabullResult: Result = stabullRouter + ? await StabullRouter.create(chainId, client) + : Result.err( + new StabullRouterError( + "Stabull router not enabled", + StabullRouterErrorType.InitializationError, + ), + ); + if (sushiResult.isErr() && balancerResult.isErr() && stabullResult.isErr()) { return Result.err( new RainSolverRouterError( "Failed initializing RainSolverRouter", RainSolverRouterErrorType.InitializationError, sushiResult.error, balancerResult.error, - ), - ); - } else if (sushiResult.isErr() && balancerResult.isOk()) { - return Result.ok( - new RainSolverRouter(chainId, client, undefined, balancerResult.value), - ); - } else if (balancerResult.isErr() && sushiResult.isOk()) { - return Result.ok(new RainSolverRouter(chainId, client, sushiResult.value, undefined)); - } else if (sushiResult.isOk() && balancerResult.isOk()) { - return Result.ok( - new RainSolverRouter(chainId, client, sushiResult.value, balancerResult.value), - ); - } else { - // unreachable path - return Result.err( - new RainSolverRouterError( - "unreachable path", - RainSolverRouterErrorType.InitializationError, + stabullResult.error, ), ); } + return Result.ok( + new RainSolverRouter( + chainId, + client, + sushiResult.isOk() ? sushiResult.value : undefined, + balancerResult.isOk() ? balancerResult.value : undefined, + stabullResult.isOk() ? stabullResult.value : undefined, + ), + ); } /** @@ -136,6 +142,7 @@ export class RainSolverRouter extends RainSolverRouterBase { const promises = [ this.sushi?.getMarketPrice(params), this.balancer?.getMarketPrice(params), + this.stabull?.getMarketPrice({ ...params, sushiRouter: this.sushi }), ]; const results = await Promise.all(promises); results.sort((a, b) => { @@ -165,7 +172,11 @@ export class RainSolverRouter extends RainSolverRouterBase { async tryQuote( params: RainSolverRouterQuoteParams, ): Promise> { - const promises = [this.sushi?.tryQuote(params), this.balancer?.tryQuote(params)]; + const promises = [ + this.sushi?.tryQuote(params), + this.balancer?.tryQuote(params), + this.stabull?.tryQuote(params), + ]; const results = await Promise.all(promises); results.sort((a, b) => { if (!a?.isOk() && !b?.isOk()) return 0; @@ -192,7 +203,11 @@ export class RainSolverRouter extends RainSolverRouterBase { async findBestRoute( params: RainSolverRouterQuoteParams, ): Promise> { - const promises = [this.sushi?.findBestRoute(params), this.balancer?.findBestRoute(params)]; + const promises = [ + this.sushi?.findBestRoute(params), + this.balancer?.findBestRoute(params), + this.stabull?.findBestRoute(params), + ]; const results = await Promise.all(promises); results.sort((a, b) => { if (!a?.isOk() && !b?.isOk()) return 0; @@ -215,7 +230,11 @@ export class RainSolverRouter extends RainSolverRouterBase { async getTradeParams( args: GetTradeParamsArgs, ): Promise> { - const promises = [this.sushi?.getTradeParams(args), this.balancer?.getTradeParams(args)]; + const promises = [ + this.sushi?.getTradeParams(args), + this.balancer?.getTradeParams(args), + this.stabull?.getTradeParams(args), + ]; const results = await Promise.all(promises); results.sort((a, b) => { if (!a?.isOk() && !b?.isOk()) return 0; @@ -240,7 +259,7 @@ export class RainSolverRouter extends RainSolverRouterBase { toToken: Token, fromToken: Token, maximumInputFixed: bigint, - gasPriceBI: bigint, + gasPrice: bigint, routeType: "single" | "multi" = "single", ): bigint | undefined { return this.sushi?.findLargestTradeSize( @@ -248,7 +267,7 @@ export class RainSolverRouter extends RainSolverRouterBase { toToken, fromToken, maximumInputFixed, - gasPriceBI, + gasPrice, routeType, ); } @@ -257,20 +276,29 @@ export class RainSolverRouter extends RainSolverRouterBase { return [ ...(this.balancer?.getLiquidityProvidersList() ?? []), ...(this.sushi?.getLiquidityProvidersList() ?? []), + ...(this.stabull?.getLiquidityProvidersList() ?? []), ]; } } function getError( msg: string, - results: (Result | undefined)[], + results: ( + | Result + | undefined + )[], ): RainSolverRouterError { let type = RainSolverRouterErrorType.FetchFailed; if ( - (results[0] as Err | undefined)?.error?.type === - SushiRouterErrorType.NoRouteFound && - (results[1] as Err | undefined)?.error?.type === - BalancerRouterErrorType.NoRouteFound + (!results[0] || + (results[0] as Err | undefined)?.error?.type === + SushiRouterErrorType.NoRouteFound) && + (!results[1] || + (results[1] as Err | undefined)?.error?.type === + BalancerRouterErrorType.NoRouteFound) && + (!results[2] || + (results[2] as Err | undefined)?.error?.type === + StabullRouterErrorType.NoRouteFound) ) { type = RainSolverRouterErrorType.NoRouteFound; } @@ -279,5 +307,6 @@ function getError( type, (results[0] as Err | undefined)?.error, (results[1] as Err | undefined)?.error, + (results[2] as Err | undefined)?.error, ); } diff --git a/src/router/stabull/error.ts b/src/router/stabull/error.ts new file mode 100644 index 00000000..ae2c4269 --- /dev/null +++ b/src/router/stabull/error.ts @@ -0,0 +1,36 @@ +import { RainSolverBaseError } from "../../error"; + +/** Enumerates the possible error types that can occur within the Stabull Router functionalities */ +export enum StabullRouterErrorType { + InitializationError, + UnsupportedChain, + NoRouteFound, + FetchFailed, + WasmEncodedError, + UndefinedTradeDestinationAddress, +} + +/** + * Represents an error type for the Stabull Router functionalities. + * This error class extends the `RainSolverBaseError` error class, with the `type` + * property indicates the specific category of the error, as defined by the + * `StabullRouterErrorType` enum. The optional `cause` property can be used to + * attach the original error or any relevant context that led to this error. + * + * @example + * ```typescript + * // without cause + * throw new StabullRouterError("msg", StabullRouterErrorType); + * + * // with cause + * throw new StabullRouterError("msg", StabullRouterErrorType, originalError); + * ``` + */ +export class StabullRouterError extends RainSolverBaseError { + type: StabullRouterErrorType; + constructor(message: string, type: StabullRouterErrorType, cause?: any) { + super(message, cause); + this.type = type; + this.name = "StabullRouterError"; + } +} diff --git a/src/router/stabull/index.test.ts b/src/router/stabull/index.test.ts new file mode 100644 index 00000000..ad122958 --- /dev/null +++ b/src/router/stabull/index.test.ts @@ -0,0 +1,544 @@ +import { ONE18 } from "../../math"; +import { Order } from "../../order"; +import { Token } from "sushi/currency"; +import { StabullConstants } from "./constants"; +import { RouterType, RouteStatus } from "../types"; +import { StabullRouter, StabullRouterQuote } from "."; +import { ABI, Result, TokenDetails } from "../../common"; +import { encodeAbiParameters, maxUint256, PublicClient } from "viem"; +import { StabullRouterError, StabullRouterErrorType } from "./error"; +import { describe, it, expect, vi, beforeEach, Mock, assert } from "vitest"; + +vi.mock("viem", async (importOriginal) => ({ + ...(await importOriginal()), + encodeAbiParameters: vi.fn().mockReturnValue("0xencodedData"), +})); + +describe("test StabullRouter", () => { + let mockClient: PublicClient; + const chainId = 1; + const mockTokenIn = new Token({ + chainId, + address: StabullConstants.Tokens[chainId].TRYB, + decimals: 18, + symbol: "TRYB", + }); + const mockTokenOut = new Token({ + chainId, + address: StabullConstants.Tokens[chainId].NZDS, + decimals: 18, + symbol: "NZDS", + }); + const mockSwapAmount = 1000000000000000000n; // 1 TRYB + const gasPrice = 20000000000n; // 20 gwei + + beforeEach(() => { + vi.clearAllMocks(); + mockClient = { + readContract: vi.fn(), + } as any; + }); + + describe("test create method", () => { + it("should successfully initialize StabullRouter for supported chain", async () => { + const result = await StabullRouter.create(chainId, mockClient); + + assert(result.isOk()); + if (result.isOk()) { + const router = result.value; + expect(router).toBeInstanceOf(StabullRouter); + expect(router.chainId).toBe(chainId); + expect(router.routerAddress).toBeDefined(); + expect(router.quoteCurrencyAddress).toBeDefined(); + } + }); + + it("should error for unsupported chain", async () => { + const chainId = 14; // Unsupported chain + const result = await StabullRouter.create(chainId, mockClient); + + assert(result.isErr()); + if (result.isErr()) { + const error = result.error; + expect(error).toBeInstanceOf(StabullRouterError); + expect(error.type).toBe(StabullRouterErrorType.UnsupportedChain); + expect(error.message).toBe( + `Chain with id of "${chainId}" is not supported by Stabull Router`, + ); + } + }); + }); + + describe("test findBestRoute method", () => { + let router: StabullRouter; + + beforeEach(async () => { + const routerResult = await StabullRouter.create(chainId, mockClient); + if (routerResult.isOk()) { + router = routerResult.value; + } + }); + + it("should successfully get best route", async () => { + (mockClient.readContract as Mock).mockResolvedValueOnce(2000000000000000000n); + + const result = await router.findBestRoute({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + assert(result.isOk()); + const route = result.value; + expect(route.amountOut).toBe(2000000000000000000n); + expect(route.price).toBe(2000000000000000000n); + expect(route.status).toBe(RouteStatus.Success); + expect(route.type).toBe(RouterType.Stabull); + expect(mockClient.readContract).toHaveBeenCalledTimes(1); + expect(mockClient.readContract).toHaveBeenCalledWith({ + abi: ABI.Stabull.Primary.Router, + address: router.routerAddress, + functionName: "viewOriginSwap", + args: [ + router.quoteCurrencyAddress, + mockTokenIn.address, + mockTokenOut.address, + mockSwapAmount, + ], + }); + }); + + it("should return error when tokens are not supported", async () => { + const unsupportedTokenIn = new Token({ + chainId: 1, + address: "0x1234567890123456789012345678901234567890" as `0x${string}`, + decimals: 18, + symbol: "UNSUPPORTED", + }); + const result = await router.findBestRoute({ + fromToken: unsupportedTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + assert(result.isErr()); + expect(result.error).toBeInstanceOf(StabullRouterError); + expect(result.error.type).toBe(StabullRouterErrorType.NoRouteFound); + expect(result.error.message).toBe( + "Cannot trade this token pair on Stabull router as one or both tokens are not supported", + ); + }); + + it("should return error when readContract fails", async () => { + (mockClient.readContract as Mock).mockRejectedValueOnce(new Error("Network error")); + const result = await router.findBestRoute({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + assert(result.isErr()); + expect(result.error).toBeInstanceOf(StabullRouterError); + expect(result.error.type).toBe(StabullRouterErrorType.FetchFailed); + expect(result.error.message).toBe( + "Failed to find route in stabull router for the given token pair", + ); + }); + }); + + describe("test tryQuote method", () => { + let router: StabullRouter; + + beforeEach(async () => { + const routerResult = await StabullRouter.create(chainId, mockClient); + if (routerResult.isOk()) { + router = routerResult.value; + } + }); + + it("should call findBestRouter correctly and return success result", async () => { + const mockResult: StabullRouterQuote = { + amountOut: 1234n, + price: 1234n, + status: RouteStatus.Success, + type: RouterType.Stabull, + }; + const spy = vi.spyOn(router, "findBestRoute"); + spy.mockResolvedValueOnce(Result.ok(mockResult)); + + const result = await router.tryQuote({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + assert(result.isOk()); + const quote = result.value; + expect(quote).toEqual(mockResult); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + spy.mockRestore(); + }); + + it("should call findBestRouter correctly and return error result", async () => { + const err = new StabullRouterError("some error", StabullRouterErrorType.FetchFailed); + const spy = vi.spyOn(router, "findBestRoute"); + spy.mockResolvedValueOnce(Result.err(err)); + + const result = await router.tryQuote({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + assert(result.isErr()); + expect(result.error).toEqual(err); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + spy.mockRestore(); + }); + }); + + describe("test getMarketPrice method", () => { + let router: StabullRouter; + + beforeEach(async () => { + const routerResult = await StabullRouter.create(chainId, mockClient); + if (routerResult.isOk()) { + router = routerResult.value; + } + }); + + it("should call findBestRouter correctly and return success result", async () => { + const mockResult: StabullRouterQuote = { + amountOut: 1000000000000000000n, + price: 1000000000000000000n, + status: RouteStatus.Success, + type: RouterType.Stabull, + }; + const spy = vi.spyOn(router, "findBestRoute"); + spy.mockResolvedValueOnce(Result.ok(mockResult)); + + const result = await router.getMarketPrice({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + assert(result.isOk()); + const marketPrice = result.value; + expect(marketPrice).toEqual({ price: "1" }); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + spy.mockRestore(); + }); + + it("should call findBestRouter correctly and return error result", async () => { + const err = new StabullRouterError("some error", StabullRouterErrorType.FetchFailed); + const spy = vi.spyOn(router, "findBestRoute"); + spy.mockResolvedValueOnce(Result.err(err)); + + const result = await router.getMarketPrice({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + assert(result.isErr()); + expect(result.error).toEqual(err); + expect(spy).toHaveBeenCalledTimes(2); + expect(spy).toHaveBeenCalledWith({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + spy.mockRestore(); + }); + }); + + describe("test getTradeParams method", () => { + let mockOrderDetails: any; + let mockGetTradeParamsArgs: any; + let router: StabullRouter; + + beforeEach(async () => { + vi.clearAllMocks(); + const routerResult = await StabullRouter.create(chainId, mockClient); + if (routerResult.isOk()) { + router = routerResult.value; + } + + // Mock order details + mockOrderDetails = { + takeOrder: { + struct: { + order: { type: Order.Type.V3 }, + inputIOIndex: 0, + outputIOIndex: 0, + signedContext: [], + }, + quote: { + ratio: 3000n * ONE18, // 3000 price ratio + }, + }, + }; + + // Mock GetTradeParamsArgs + mockGetTradeParamsArgs = { + state: { + gasPrice, + appOptions: { + maxRatio: true, + }, + watchedTokens: new Map([ + [ + mockTokenIn.address.toLowerCase(), + { + address: mockTokenIn.address, + decimals: mockTokenIn.decimals, + symbol: mockTokenIn.symbol, + } as any, + ], + [ + mockTokenOut.address.toLowerCase(), + { + address: mockTokenOut.address, + decimals: mockTokenOut.decimals, + symbol: mockTokenOut.symbol, + } as any, + ], + ]), + }, + maximumInput: mockSwapAmount, + orderDetails: mockOrderDetails, + toToken: mockTokenOut, + fromToken: mockTokenIn, + signer: { + account: { + address: "0xsignerAddress" as `0x${string}`, + }, + }, + isPartial: false, + }; + }); + + it("should successfully return trade params for full trade", async () => { + const mockQuote = { + type: RouterType.Stabull as const, + status: RouteStatus.Success, + price: 3000n * ONE18, + amountOut: 3000000000n, + }; + const tryQuoteSpy = vi.spyOn(router, "tryQuote"); + tryQuoteSpy.mockResolvedValue(Result.ok(mockQuote)); + + const result = await router.getTradeParams(mockGetTradeParamsArgs); + + assert(result.isOk()); + const tradeParams = result.value; + + expect(tradeParams.type).toBe(RouterType.Stabull); + expect(tradeParams.quote).toEqual(mockQuote); + expect(tradeParams.routeVisual).toEqual([]); + expect(tradeParams.takeOrdersConfigStruct.minimumInput).toBe(1n); + expect(tradeParams.takeOrdersConfigStruct.maximumInput).toBe(maxUint256); + expect(tradeParams.takeOrdersConfigStruct.maximumIORatio).toBe(maxUint256); + expect(tradeParams.takeOrdersConfigStruct.orders).toEqual([ + mockOrderDetails.takeOrder.struct, + ]); + expect(tradeParams.takeOrdersConfigStruct.data).toBe("0xencodedData"); + + expect(encodeAbiParameters).toHaveBeenCalledWith( + [{ type: "address" }], + [router.quoteCurrencyAddress], + ); + expect(tryQuoteSpy).toHaveBeenCalledWith({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + tryQuoteSpy.mockRestore(); + }); + + it("should successfully return trade params for partial trade size and maxRatio false", async () => { + const mockQuote = { + type: RouterType.Stabull as const, + status: RouteStatus.Success, + price: 3000n * ONE18, + amountOut: 3000000000n, + }; + mockGetTradeParamsArgs.isPartial = true; + mockGetTradeParamsArgs.state.appOptions.maxRatio = false; + const tryQuoteSpy = vi.spyOn(router, "tryQuote"); + tryQuoteSpy.mockResolvedValue(Result.ok(mockQuote)); + + const result = await router.getTradeParams(mockGetTradeParamsArgs); + + assert(result.isOk()); + const tradeParams = result.value; + + expect(tradeParams.type).toBe(RouterType.Stabull); + expect(tradeParams.quote).toEqual(mockQuote); + expect(tradeParams.routeVisual).toEqual([]); + expect(tradeParams.takeOrdersConfigStruct.minimumInput).toBe(1n); + expect(tradeParams.takeOrdersConfigStruct.maximumInput).toBe(mockSwapAmount); + expect(tradeParams.takeOrdersConfigStruct.maximumIORatio).toBe(mockQuote.price); + expect(tradeParams.takeOrdersConfigStruct.orders).toEqual([ + mockOrderDetails.takeOrder.struct, + ]); + expect(tradeParams.takeOrdersConfigStruct.data).toBe("0xencodedData"); + + expect(encodeAbiParameters).toHaveBeenCalledWith( + [{ type: "address" }], + [router.quoteCurrencyAddress], + ); + expect(tryQuoteSpy).toHaveBeenCalledWith({ + fromToken: mockTokenIn, + toToken: mockTokenOut, + amountIn: mockSwapAmount, + gasPrice, + }); + + tryQuoteSpy.mockRestore(); + }); + + it("should return error when tryQuote fails", async () => { + const mockError = new StabullRouterError( + "No route found", + StabullRouterErrorType.NoRouteFound, + ); + const tryQuoteSpy = vi.spyOn(router, "tryQuote"); + tryQuoteSpy.mockResolvedValue(Result.err(mockError)); + + const result = await router.getTradeParams(mockGetTradeParamsArgs); + + assert(result.isErr()); + expect(result.error).toBe(mockError); + expect(result.error.type).toBe(StabullRouterErrorType.NoRouteFound); + + tryQuoteSpy.mockRestore(); + }); + + it("should return error when getTakeOrdersConfig fails", async () => { + const mockQuote = { + type: RouterType.Stabull as const, + status: RouteStatus.Success, + price: 3000n * ONE18, + amountOut: 3000000000n, + }; + const tryQuoteSpy = vi.spyOn(router, "tryQuote"); + tryQuoteSpy.mockResolvedValue(Result.ok(mockQuote)); + + const getTakeOrdersConfigSpy = vi.spyOn(router, "getTakeOrdersConfig"); + getTakeOrdersConfigSpy.mockReturnValue( + Result.err({ msg: "", readableMsg: "some error" }), + ); + + const result = await router.getTradeParams(mockGetTradeParamsArgs); + + assert(result.isErr()); + expect(result.error.message).toContain("Failed to build TakeOrdersConfig struct"); + expect(result.error.type).toBe(StabullRouterErrorType.WasmEncodedError); + expect(result.error.cause).toEqual({ msg: "", readableMsg: "some error" }); + expect(getTakeOrdersConfigSpy).toHaveBeenCalledWith( + mockGetTradeParamsArgs.orderDetails, + mockGetTradeParamsArgs.maximumInput, + mockQuote.price, + "0xencodedData", + mockGetTradeParamsArgs.state.appOptions.maxRatio, + mockGetTradeParamsArgs.isPartial, + ); + + tryQuoteSpy.mockRestore(); + getTakeOrdersConfigSpy.mockRestore(); + }); + }); + + describe("test canTrade static method", () => { + const supportedChainId = 1; // Ethereum mainnet + const unsupportedChainId = 999; // Unsupported chain + + // Valid addresses from StabullConstants for chainId 1 + const validTokenAddress1 = StabullConstants.Tokens[1].TRYB.toLowerCase() as `0x${string}`; + const validTokenAddress2 = StabullConstants.Tokens[1].NZDS.toLowerCase() as `0x${string}`; + + // Invalid token addresses + const invalidTokenAddress1 = "0x1234567890123456789012345678901234567890" as `0x${string}`; + const invalidTokenAddress2 = + "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef" as `0x${string}`; + + it("should return true when both tokens are supported on supported chain", () => { + const result = StabullRouter.canTrade( + validTokenAddress1, + validTokenAddress2, + supportedChainId, + ); + expect(result).toBe(true); + }); + + it("should return false when fromToken is not supported on supported chain", () => { + const result = StabullRouter.canTrade( + invalidTokenAddress1, + validTokenAddress2, + supportedChainId, + ); + expect(result).toBe(false); + }); + + it("should return false when toToken is not supported on supported chain", () => { + const result = StabullRouter.canTrade( + validTokenAddress1, + invalidTokenAddress2, + supportedChainId, + ); + expect(result).toBe(false); + }); + + it("should return false when both tokens are not supported on supported chain", () => { + const result = StabullRouter.canTrade( + invalidTokenAddress1, + invalidTokenAddress2, + supportedChainId, + ); + expect(result).toBe(false); + }); + + it("should return false when chain is not supported regardless of tokens", () => { + const result = StabullRouter.canTrade( + validTokenAddress1, + validTokenAddress2, + unsupportedChainId, + ); + expect(result).toBe(false); + }); + }); +}); diff --git a/src/router/stabull/index.ts b/src/router/stabull/index.ts new file mode 100644 index 00000000..60d697d2 --- /dev/null +++ b/src/router/stabull/index.ts @@ -0,0 +1,269 @@ +import { USDC } from "sushi/currency"; +import { ABI, Result } from "../../common"; +import { calculatePrice18, ONE18 } from "../../math"; +import { StabullConstants } from "./constants"; +import { TakeOrdersConfigType } from "../../order/types"; +import { StabullRouterError, StabullRouterErrorType } from "./error"; +import { + Chain, + Account, + Transport, + parseUnits, + formatUnits, + PublicClient, + encodeAbiParameters, +} from "viem"; +import { + RouterType, + RouteStatus, + GetTradeParamsArgs, + RainSolverRouterBase, + RainSolverRouterQuoteParams, +} from "../types"; + +/** Represents the parameters for quoting Stabull */ +export type StabullQuoteParams = RainSolverRouterQuoteParams; + +/** Represents the quote details for a Stabull route */ +export type StabullRouterQuote = { + /** The router type */ + type: RouterType.Stabull; + /** The status of the route */ + status: RouteStatus; + /** The price of the route */ + price: bigint; + /** The amount out for the given amount in of the route */ + amountOut: bigint; +}; + +/** Represents the trade params for a Stabull route */ +export type StabullTradeParams = { + /** The router type */ + type: RouterType.Stabull; + /** The quote details for the Stabull route */ + quote: StabullRouterQuote; + /** The visual representation of the route */ + routeVisual: string[]; + /** The TakeOrdersConfig struct for onchain execution */ + takeOrdersConfigStruct: TakeOrdersConfigType; +}; + +/** + * The Stabull Router class provides methods to interact with the stabull router library, mainly `RainDataFetcher`, + * including fetching and syncing pool data, getting best route and market price. + */ +export class StabullRouter extends RainSolverRouterBase { + /** The address of the router contract */ + readonly routerAddress: `0x${string}`; + /** The address of the quote currency, usually USDC as per Stabull docs */ + readonly quoteCurrencyAddress: `0x${string}`; + + constructor( + chainId: number, + client: PublicClient, + ) { + super(chainId, client); + this.routerAddress = + StabullConstants.Routers[chainId as keyof typeof StabullConstants.Routers]; + this.quoteCurrencyAddress = + StabullConstants.QuoteCurrency[chainId as keyof typeof StabullConstants.QuoteCurrency]; + } + + /** + * Tries to initialize the Stabull Router instance from the given params + * @param chainId - The chain id of the operating chain + * @param client - A viem client instance + * @returns A Result containing the Stabull Router instance or an error + */ + static async create( + chainId: number, + client: PublicClient, + ): Promise> { + if (!StabullConstants.isChainSupported(chainId)) { + return Result.err( + new StabullRouterError( + `Chain with id of "${chainId}" is not supported by Stabull Router`, + StabullRouterErrorType.UnsupportedChain, + ), + ); + } + + return Result.ok(new StabullRouter(chainId, client)); + } + + /** Gets the list of this liquidity provider */ + getLiquidityProvidersList(): string[] { + return ["Stabull"]; + } + + /** + * Gets the market price for a token pair and swap amount. + * @param params The parameters for the market price query + * @returns The formatted market price for the token pair + */ + async getMarketPrice( + params: StabullQuoteParams, + ): Promise> { + // return early if from and to tokens are the same + if (params.fromToken.address.toLowerCase() === params.toToken.address.toLowerCase()) { + return Result.ok({ price: "1" }); + } + + const quoteResult = await this.findBestRoute(params); + if (quoteResult.isErr()) { + const toUsdcQuote = await this.findBestRoute({ + ...params, + toToken: USDC[this.chainId as keyof typeof USDC], + }); + if (!toUsdcQuote?.isOk()) { + return Result.err(quoteResult.error); + } + const FromUsdcPrice = await params.sushiRouter?.getMarketPrice({ + ...params, + fromToken: USDC[this.chainId as keyof typeof USDC], + }); + if (!FromUsdcPrice?.isOk()) { + return Result.err(quoteResult.error); + } + + const price = + (toUsdcQuote.value.price * parseUnits(FromUsdcPrice.value.price, 18)) / ONE18; + return Result.ok({ price: formatUnits(price, 18) }); + } + return Result.ok({ price: formatUnits(quoteResult.value.price, 18) }); + } + + /** + * Gets the Stabull market quote for a token pair by simulating Stabull swap query + * @param params The parameters for getting the best Stabull market quote + */ + async tryQuote( + params: StabullQuoteParams, + ): Promise> { + const quoteResult = await this.findBestRoute(params); + if (quoteResult.isErr()) { + return Result.err(quoteResult.error); + } + return Result.ok(quoteResult.value); + } + + /** + * Finds the best Stabull route for a given token pair and swap amount + * @param params The parameters for getting the best Stabull route + */ + async findBestRoute( + params: StabullQuoteParams, + ): Promise> { + const { fromToken, toToken, amountIn } = params; + + // exit early if token pair (at least one of the tokens of the trade) is not supported by Stabull + if (!StabullRouter.canTrade(fromToken.address, toToken.address, this.chainId)) { + return Result.err( + new StabullRouterError( + "Cannot trade this token pair on Stabull router as one or both tokens are not supported", + StabullRouterErrorType.NoRouteFound, + ), + ); + } + + // try to find a route using the Stabull router by calling the router contract quote function + try { + const result = await this.client.readContract({ + abi: ABI.Stabull.Primary.Router, + address: this.routerAddress, + functionName: "viewOriginSwap", + args: [this.quoteCurrencyAddress, fromToken.address, toToken.address, amountIn], + }); + const price = calculatePrice18(amountIn, result, fromToken.decimals, toToken.decimals); + return Result.ok({ + type: RouterType.Stabull, + status: RouteStatus.Success, + price, + amountOut: result, + }); + } catch (error) { + return Result.err( + new StabullRouterError( + "Failed to find route in stabull router for the given token pair", + StabullRouterErrorType.FetchFailed, + error, + ), + ); + } + } + + /** + * Gets the trade parameters for the best possible market quote for + * executing a trade against Stabull Router with the returned value. + * @param args - The trade arguments + */ + async getTradeParams( + args: GetTradeParamsArgs, + ): Promise> { + const { state, maximumInput, orderDetails, toToken, fromToken, isPartial } = args; + const gasPrice = state.gasPrice; + + // get route details from stabull dataFetcher + const quoteResult = await this.tryQuote({ + fromToken, + toToken, + amountIn: maximumInput, + gasPrice, + }); + + // exit early if no route found + if (quoteResult.isErr()) { + return Result.err(quoteResult.error); + } + const quote = quoteResult.value; + + const takeOrdersConfigStructResult = this.getTakeOrdersConfig( + orderDetails, + maximumInput, + quote.price, + encodeAbiParameters([{ type: "address" }], [this.quoteCurrencyAddress]), + state.appOptions.maxRatio, + isPartial, + ); + if (takeOrdersConfigStructResult.isErr()) { + return Result.err( + new StabullRouterError( + "Failed to build TakeOrdersConfig struct", + StabullRouterErrorType.WasmEncodedError, + takeOrdersConfigStructResult.error, + ), + ); + } + const takeOrdersConfigStruct = takeOrdersConfigStructResult.value; + + return Result.ok({ + type: RouterType.Stabull, + quote, + routeVisual: [], + takeOrdersConfigStruct, + }); + } + + /** + * Checks if a trade can take place between the given `from/to` tokens on Stabull + * protocol as Stabull only supports a limited set of tokens on each chain. + * @param fromToken - The token to be sold in the swap + * @param toToken - The token to be received in the swap + * @param chainId - The chain id of the operating chain + * @returns True if the trade is possible for the given token pair, false otherwise + */ + static canTrade(fromToken: `0x${string}`, toToken: `0x${string}`, chainId: number): boolean { + if ( + StabullConstants.isChainSupported(chainId) && + StabullConstants.TokenList[chainId as keyof typeof StabullConstants.TokenList].has( + fromToken.toLowerCase(), + ) && + StabullConstants.TokenList[chainId as keyof typeof StabullConstants.TokenList].has( + toToken.toLowerCase(), + ) + ) { + return true; + } + return false; + } +} diff --git a/src/router/types.ts b/src/router/types.ts index aab2de4a..3c0cab67 100644 --- a/src/router/types.ts +++ b/src/router/types.ts @@ -2,7 +2,7 @@ import { SharedState } from "../state"; import { Token } from "sushi/currency"; import { RainSolverSigner } from "../signer"; import { WasmEncodedError } from "@rainlanguage/float"; -import { SushiRouterQuote, SushiTradeParams } from "./sushi"; +import { SushiRouter, SushiRouterQuote, SushiTradeParams } from "./sushi"; import { maxFloat, minFloat, Result, toFloat } from "../common"; import { BalancerRouterQuote, BalancerTradeParams } from "./balancer"; import { Account, Chain, maxUint256, PublicClient, Transport } from "viem"; @@ -15,6 +15,7 @@ import { TakeOrdersConfigTypeV4, } from "../order"; import { RainSolverRouterError } from "./error"; +import { StabullRouterQuote, StabullTradeParams } from "./stabull"; /** Represents the different router types */ export enum RouterType { @@ -22,6 +23,8 @@ export enum RouterType { Sushi = "sushi", /** The Balancer router (BatchRouter) */ Balancer = "balancer", + /** The Stabull router */ + Stabull = "stabull", } /** Represents the status of a route */ @@ -41,6 +44,7 @@ export type RainSolverRouterQuoteParams = { blockNumber?: bigint; senderAddress?: `0x${string}`; sushiRouteType?: "single" | "multi"; + sushiRouter?: SushiRouter; }; /** Arguments for simulating a trade against routers */ @@ -64,10 +68,10 @@ export type GetTradeParamsArgs = { }; /** Represents the trade params for a RainSolverRouter route */ -export type TradeParamsType = SushiTradeParams | BalancerTradeParams; +export type TradeParamsType = SushiTradeParams | BalancerTradeParams | StabullTradeParams; /** Represents the quote details for a RainSolverRouter route */ -export type RainSolverRouterQuote = SushiRouterQuote | BalancerRouterQuote; +export type RainSolverRouterQuote = SushiRouterQuote | BalancerRouterQuote | StabullRouterQuote; /** * Base class for all RainSolverRouter implementations. @@ -132,7 +136,7 @@ export abstract class RainSolverRouterBase { * @param toToken - The token to trade to * @param fromToken - The token to trade from * @param maximumInputFixed - The maximum input amount (in 18 decimals) - * @param gasPriceBI - The current gas price (in bigint) + * @param gasPrice - The current gas price (in bigint) * @param routeType - The route type, single or multi */ findLargestTradeSize( @@ -140,7 +144,7 @@ export abstract class RainSolverRouterBase { toToken: Token, fromToken: Token, maximumInputFixed: bigint, - gasPriceBI: bigint, + gasPrice: bigint, routeType: "single" | "multi", ): bigint | undefined { // default implementation returns undefined, override in subclass if supported @@ -148,7 +152,7 @@ export abstract class RainSolverRouterBase { toToken; fromToken; maximumInputFixed; - gasPriceBI; + gasPrice; routeType; return undefined; } diff --git a/src/state/index.test.ts b/src/state/index.test.ts index d224fa5b..00667080 100644 --- a/src/state/index.test.ts +++ b/src/state/index.test.ts @@ -136,6 +136,7 @@ describe("Test SharedStateConfig tryFromAppOptions", () => { expect(spy).toHaveBeenCalledWith({ chainId: 1, client: mockClient, + stabullRouter: false, sushiRouterConfig: { liquidityProviders: [LiquidityProviders.UniswapV2], sushiRouteProcessor4Address: "0xrouteProcessor", @@ -167,6 +168,7 @@ describe("Test SharedStateConfig tryFromAppOptions", () => { expect(spy).toHaveBeenCalledWith({ chainId: 1, client: mockClient, + stabullRouter: false, sushiRouterConfig: { liquidityProviders: [LiquidityProviders.UniswapV2], sushiRouteProcessor4Address: "0xrouteProcessor", @@ -187,11 +189,12 @@ describe("Test SharedStateConfig tryFromAppOptions", () => { expect(spy).toHaveBeenCalledWith({ chainId: 1, client: mockClient, + stabullRouter: false, sushiRouterConfig: { liquidityProviders: [LiquidityProviders.UniswapV2], sushiRouteProcessor4Address: "0xrouteProcessor", }, - undefined, + balancerRouterConfig: undefined, }); spy.mockRestore(); @@ -207,11 +210,12 @@ describe("Test SharedStateConfig tryFromAppOptions", () => { expect(spy).toHaveBeenCalledWith({ chainId: 99999, client: mockClient, + stabullRouter: false, sushiRouterConfig: { liquidityProviders: [LiquidityProviders.UniswapV2], sushiRouteProcessor4Address: "0xrouteProcessor", }, - undefined, + balancerRouterConfig: undefined, }); spy.mockRestore(); diff --git a/src/state/index.ts b/src/state/index.ts index 62640a5a..173d0986 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -135,6 +135,8 @@ export namespace SharedStateConfig { const routerResult = await RainSolverRouter.create({ chainId, client, + stabullRouter: + options.contracts.v4?.stabullArb || options.contracts.v5?.stabullArb ? true : false, sushiRouterConfig: { liquidityProviders, sushiRouteProcessor4Address: chainConfig.routeProcessors["4"] as `0x${string}`, diff --git a/test/abis/StabullRouterOrderBookV5ArbOrderTaker.json b/test/abis/StabullRouterOrderBookV5ArbOrderTaker.json new file mode 100644 index 00000000..549b5e54 --- /dev/null +++ b/test/abis/StabullRouterOrderBookV5ArbOrderTaker.json @@ -0,0 +1 @@ +{"abi":[{"type":"constructor","inputs":[{"name":"config","type":"tuple","internalType":"struct OrderBookV5ArbConfig","components":[{"name":"orderBook","type":"address","internalType":"address"},{"name":"task","type":"tuple","internalType":"struct TaskV2","components":[{"name":"evaluable","type":"tuple","internalType":"struct EvaluableV4","components":[{"name":"interpreter","type":"address","internalType":"contract IInterpreterV4"},{"name":"store","type":"address","internalType":"contract IInterpreterStoreV3"},{"name":"bytecode","type":"bytes","internalType":"bytes"}]},{"name":"signedContext","type":"tuple[]","internalType":"struct SignedContextV1[]","components":[{"name":"signer","type":"address","internalType":"address"},{"name":"context","type":"bytes32[]","internalType":"bytes32[]"},{"name":"signature","type":"bytes","internalType":"bytes"}]}]},{"name":"implementationData","type":"bytes","internalType":"bytes"}]}],"stateMutability":"nonpayable"},{"type":"fallback","stateMutability":"nonpayable"},{"type":"function","name":"arb4","inputs":[{"name":"orderBook","type":"address","internalType":"contract IOrderBookV5"},{"name":"takeOrders","type":"tuple","internalType":"struct TakeOrdersConfigV4","components":[{"name":"minimumInput","type":"bytes32","internalType":"Float"},{"name":"maximumInput","type":"bytes32","internalType":"Float"},{"name":"maximumIORatio","type":"bytes32","internalType":"Float"},{"name":"orders","type":"tuple[]","internalType":"struct TakeOrderConfigV4[]","components":[{"name":"order","type":"tuple","internalType":"struct OrderV4","components":[{"name":"owner","type":"address","internalType":"address"},{"name":"evaluable","type":"tuple","internalType":"struct EvaluableV4","components":[{"name":"interpreter","type":"address","internalType":"contract IInterpreterV4"},{"name":"store","type":"address","internalType":"contract IInterpreterStoreV3"},{"name":"bytecode","type":"bytes","internalType":"bytes"}]},{"name":"validInputs","type":"tuple[]","internalType":"struct IOV2[]","components":[{"name":"token","type":"address","internalType":"address"},{"name":"vaultId","type":"bytes32","internalType":"bytes32"}]},{"name":"validOutputs","type":"tuple[]","internalType":"struct IOV2[]","components":[{"name":"token","type":"address","internalType":"address"},{"name":"vaultId","type":"bytes32","internalType":"bytes32"}]},{"name":"nonce","type":"bytes32","internalType":"bytes32"}]},{"name":"inputIOIndex","type":"uint256","internalType":"uint256"},{"name":"outputIOIndex","type":"uint256","internalType":"uint256"},{"name":"signedContext","type":"tuple[]","internalType":"struct SignedContextV1[]","components":[{"name":"signer","type":"address","internalType":"address"},{"name":"context","type":"bytes32[]","internalType":"bytes32[]"},{"name":"signature","type":"bytes","internalType":"bytes"}]}]},{"name":"data","type":"bytes","internalType":"bytes"}]},{"name":"task","type":"tuple","internalType":"struct TaskV2","components":[{"name":"evaluable","type":"tuple","internalType":"struct EvaluableV4","components":[{"name":"interpreter","type":"address","internalType":"contract IInterpreterV4"},{"name":"store","type":"address","internalType":"contract IInterpreterStoreV3"},{"name":"bytecode","type":"bytes","internalType":"bytes"}]},{"name":"signedContext","type":"tuple[]","internalType":"struct SignedContextV1[]","components":[{"name":"signer","type":"address","internalType":"address"},{"name":"context","type":"bytes32[]","internalType":"bytes32[]"},{"name":"signature","type":"bytes","internalType":"bytes"}]}]}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"iStabullRouter","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IStabullRouter"}],"stateMutability":"view"},{"type":"function","name":"iTaskHash","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"onTakeOrders2","inputs":[{"name":"inputToken","type":"address","internalType":"address"},{"name":"outputToken","type":"address","internalType":"address"},{"name":"inputAmountSent","type":"bytes32","internalType":"Float"},{"name":"totalOutputAmount","type":"bytes32","internalType":"Float"},{"name":"takeOrdersData","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"event","name":"Construct","inputs":[{"name":"sender","type":"address","indexed":false,"internalType":"address"},{"name":"config","type":"tuple","indexed":false,"internalType":"struct OrderBookV5ArbConfig","components":[{"name":"orderBook","type":"address","internalType":"address"},{"name":"task","type":"tuple","internalType":"struct TaskV2","components":[{"name":"evaluable","type":"tuple","internalType":"struct EvaluableV4","components":[{"name":"interpreter","type":"address","internalType":"contract IInterpreterV4"},{"name":"store","type":"address","internalType":"contract IInterpreterStoreV3"},{"name":"bytecode","type":"bytes","internalType":"bytes"}]},{"name":"signedContext","type":"tuple[]","internalType":"struct SignedContextV1[]","components":[{"name":"signer","type":"address","internalType":"address"},{"name":"context","type":"bytes32[]","internalType":"bytes32[]"},{"name":"signature","type":"bytes","internalType":"bytes"}]}]},{"name":"implementationData","type":"bytes","internalType":"bytes"}]}],"anonymous":false},{"type":"error","name":"CoefficientOverflow","inputs":[{"name":"signedCoefficient","type":"int256","internalType":"int256"},{"name":"exponent","type":"int256","internalType":"int256"}]},{"type":"error","name":"ExponentOverflow","inputs":[{"name":"signedCoefficient","type":"int256","internalType":"int256"},{"name":"exponent","type":"int256","internalType":"int256"}]},{"type":"error","name":"InvalidSignature","inputs":[{"name":"i","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"NegativeFixedDecimalConversion","inputs":[{"name":"signedCoefficient","type":"int256","internalType":"int256"},{"name":"exponent","type":"int256","internalType":"int256"}]},{"type":"error","name":"NoOrders","inputs":[]},{"type":"error","name":"WrongTask","inputs":[]}],"bytecode":{"object":"0x60c0604052600060805234801561001557600080fd5b506040516131d93803806131d983398101604081905261003491610396565b808060016000819055507f3a5f92e1700a303557ddae1bed800da2d50036e5b24950a948611540f0928e79338260405161006f92919061060f565b60405180910390a16020810151516040015151156100b65760208082015160405161009a920161066f565b60408051601f1981840301815291905280516020909101206080525b5050600081604001518060200190518101906100d29190610689565b6001600160a01b031660a052506106a69050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b038111828210171561011e5761011e6100e6565b60405290565b604080519081016001600160401b038111828210171561011e5761011e6100e6565b604051601f8201601f191681016001600160401b038111828210171561016e5761016e6100e6565b604052919050565b6001600160a01b038116811461018b57600080fd5b50565b60005b838110156101a9578181015183820152602001610191565b50506000910152565b600082601f8301126101c357600080fd5b81516001600160401b038111156101dc576101dc6100e6565b6101ef601f8201601f1916602001610146565b81815284602083860101111561020457600080fd5b61021582602083016020870161018e565b949350505050565b60006001600160401b03821115610236576102366100e6565b5060051b60200190565b600082601f83011261025157600080fd5b815160206102666102618361021d565b610146565b82815260059290921b8401810191818101908684111561028557600080fd5b8286015b8481101561038b5780516001600160401b03808211156102a857600080fd5b908801906060828b03601f190112156102c15760008081fd5b6102c96100fc565b868301516102d681610176565b8152604083810151838111156102ec5760008081fd5b8401603f81018d136102fe5760008081fd5b8881015161030e6102618261021d565b81815260059190911b82018301908a8101908f83111561032e5760008081fd5b928401925b8284101561034c5783518252928b0192908b0190610333565b858c01525050506060840151838111156103665760008081fd5b6103748d8a838801016101b2565b918301919091525085525050918301918301610289565b509695505050505050565b600060208083850312156103a957600080fd5b82516001600160401b03808211156103c057600080fd5b90840190606082870312156103d457600080fd5b6103dc6100fc565b82516103e781610176565b815282840151828111156103fa57600080fd5b83016040818903121561040c57600080fd5b610414610124565b81518481111561042357600080fd5b82016060818b03121561043557600080fd5b61043d6100fc565b815161044881610176565b81528188015161045781610176565b8189015260408201518681111561046d57600080fd5b6104798c8285016101b2565b604083015250825250818601518481111561049357600080fd5b61049f8a828501610240565b87830152508086840152505060408301519350818411156104bf57600080fd5b6104cb878585016101b2565b60408201529695505050505050565b600081518084526104f281602086016020860161018e565b601f01601f19169290920160200192915050565b6000604082516040855260018060a01b03808251166040870152602080830151606083821660608a015260408501519450606060808a015261054b60a08a01866104da565b888401518a82038b86015280518083529196508401925083860190600581901b870185016000805b838110156105fd57898303601f19018552865180518a168452888101518985018890528051888601819052908a0190849060808701905b808310156105ca5783518252928c019260019290920191908c01906105aa565b508e84015193508681038f8801526105e281856104da565b96505050505087870196508785019450600181019050610573565b50909c9b505050505050505050505050565b6001600160a01b0383811682526040602080840182905284519092169083015282015160608083015260009061064860a0840182610506565b90506040840151603f1984830301608085015261066582826104da565b9695505050505050565b6020815260006106826020830184610506565b9392505050565b60006020828403121561069b57600080fd5b815161068281610176565b60805160a051612ae56106f460003960008181610124015281816105480152818161057d015281816106e3015261076301526000818160e20152818161020e015261025f0152612ae56000f3fe60806040526004361061005a5760003560e01c8063691f9ed711610043578063691f9ed7146100b057806393be095e146100d0578063b8757e06146101125761005a565b806301ffc9a7146100685780634ed394611461009d575b34801561006657600080fd5b005b34801561007457600080fd5b50610088610083366004611b3d565b61015e565b60405190151581526020015b60405180910390f35b6100666100ab366004611b86565b6101fb565b3480156100bc57600080fd5b506100666100cb366004611c0b565b610539565b3480156100dc57600080fd5b506101047f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610094565b34801561011e57600080fd5b506101467f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610094565b60006001600160e01b031982167f691f9ed70000000000000000000000000000000000000000000000000000000014806101c157506001600160e01b031982167f4ed3946100000000000000000000000000000000000000000000000000000000145b806101f557507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b610203610797565b61020c81611f33565b7f0000000000000000000000000000000000000000000000000000000000000000158015906102815750806040516020016102479190612081565b604051602081830303815290604052805190602001207f000000000000000000000000000000000000000000000000000000000000000014155b156102b8576040517f8812562900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102c56060840184612160565b9050600003610300576040517f9c95219f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061030f6060850185612160565b6000818110610320576103206121aa565b905060200281019061033291906121c0565b61033c90806121e0565b61034a9060408101906121f6565b6103576060870187612160565b6000818110610368576103686121aa565b905060200281019061037a91906121c0565b6020013581811061038d5761038d6121aa565b6103a39260206040909202019081019150612240565b905060006103b46060860186612160565b60008181106103c5576103c56121aa565b90506020028101906103d791906121c0565b6103e190806121e0565b6103ef9060608101906121f6565b6103fc6060880188612160565b600081811061040d5761040d6121aa565b905060200281019061041f91906121c0565b60400135818110610432576104326121aa565b6104489260206040909202019081019150612240565b905061045f6001600160a01b0383168760006107f5565b6104756001600160a01b038316876000196107f5565b600080876001600160a01b031663d0f7a862886040518263ffffffff1660e01b81526004016104a491906124af565b60408051808303816000875af11580156104c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e6919061268f565b90925090506105006001600160a01b0385168960006107f5565b61052561050c87611f33565b8561051687610976565b8661052088610976565b610a10565b50505050506105346001600055565b505050565b61056e6001600160a01b0387167f000000000000000000000000000000000000000000000000000000000000000060006107f5565b6105a46001600160a01b0387167f00000000000000000000000000000000000000000000000000000000000000006000196107f5565b60006105b282840184612240565b9050600080610622878a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061d91906126b3565b610cba565b9150915060008061066b888b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f9573d6000803e3d6000fd5b9150915080610682578161067e816126ec565b9250505b6040517f9d73b3250000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301528c811660248301528b81166044830152606482018690526084820184905260001960a48301526000917f000000000000000000000000000000000000000000000000000000000000000090911690639d73b3259060c4016020604051808303816000875af115801561072e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107529190612705565b90506107896001600160a01b038d167f000000000000000000000000000000000000000000000000000000000000000060006107f5565b505050505050505050505050565b6002600054036107ee5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600055565b80158061088857506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015610862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108869190612705565b155b6108fa5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084016107e5565b6040516001600160a01b0383166024820152604481018290526105349084907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610ce8565b6040517f54636d2b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152600090734f1c29faab7eddf8d7794695d8259996734cc665906354636d2b906024016020604051808303816000875af11580156109ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f591906126b3565b604080516001808252818301909252600091816020015b6060815260200190600190039081610a27575050604080516003808252608082019092529192506000919060208201606080368337019050506040516370a0823160e01b81523060048201529091506000906001600160a01b038816906370a0823190602401602060405180830381865afa158015610aaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ace9190612705565b90508015610aea57610aea6001600160a01b0388163383610dd0565b600080610af78389610e19565b915091508184600081518110610b0f57610b0f6121aa565b602090810291909101015250506040516370a0823160e01b8152306004820152600091506001600160a01b038616906370a0823190602401602060405180830381865afa158015610b64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b889190612705565b90508015610ba457610ba46001600160a01b0386163383610dd0565b600080610bb18387610e19565b915091508184600181518110610bc957610bc96121aa565b602090810291909101015250479150610be490503382610e5d565b610bf081601119610f76565b82600281518110610c0357610c036121aa565b602002602001018181525050508082600081518110610c2457610c246121aa565b6020908102919091010152604080516001808252818301909252600091816020015b6040805160a08101825260009181018281526060808301939093526080820183905281526020810191909152815260200190600190039081610c465790505090508781600081518110610c9b57610c9b6121aa565b6020026020010181905250610cb08382610fd2565b5050505050505050565b6000806001600160e01b038416601b0b60e085901d610cda8282876111c3565b9350935050505b9250929050565b6000610d3d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166112e49092919063ffffffff16565b9050805160001480610d5e575080806020019051810190610d5e919061271e565b6105345760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107e5565b6040516001600160a01b0383166024820152604481018290526105349084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161093f565b6000806000806000610e2b87876112fb565b925092509250600080610e3e8585611359565b9150915081838015610e4d5750815b9650965050505050509250929050565b80471015610ead5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016107e5565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610efa576040519150601f19603f3d011682016040523d82523d6000602084013e610eff565b606091505b50509050806105345760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016107e5565b6000806000610f858585611359565b9150915080610fca576040517f22c9f7bb00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044016107e5565b509392505050565b3360008181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b8651811015610cb05786818151811061103a5761103a6121aa565b6020026020010151935060008460000151604001515111156111bb576000808560000151600001516001600160a01b031663d04dfe236040518060e001604052808960000151602001516001600160a01b031681526020018a81526020018960000151604001518152602001600081526020016110bb8e8b60200151611436565b8152602001888152602001878152506040518263ffffffff1660e01b81526004016110e6919061279a565b600060405180830381865afa158015611103573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261112b919081019061289f565b80519193509150156111b8578551602001516040517f04b19db40000000000000000000000000000000000000000000000000000000081526001600160a01b03909116906304b19db490611185908b90859060040161295b565b600060405180830381600087803b15801561119f57600080fd5b505af11580156111b3573d6000803e3d6000fd5b505050505b50505b60010161101f565b600080600085121561120b576040517f4a7d166b00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044016107e5565b8460000361121f57506000905060016112dc565b8460ff84168501858112156112515760405163d556b11160e01b815260048101889052602481018790526044016107e5565b60008060008312156112a157604c198312156112775760008095509550505050506112dc565b82600003600a0a915081848161128f5761128f612974565b04955050840290911491506112dc9050565b60008313156112d1576112b583600a612a6e565b91506112c18285612a7a565b9550600194506112dc9350505050565b509193506001925050505b935093915050565b60606112f3848460008561173c565b949350505050565b6000808060ff841681037f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86111561134857600a860460018201600a880660001493509350935050611352565b8593509150600190505b9250925092565b6000601b83900b83148383826113be577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561139e57620186a0860595506005850194505b8586601b0b146113b957600a8605955084600101945061139e565b6113d6565b856000036113d657506000925060019150610ce19050565b848560030b1461141b5760008512156113f8575060009250829150610ce19050565b60405163d556b11160e01b815260048101839052602481018290526044016107e5565b50506001600160e01b03841660e084901b1791509250929050565b60606000825167ffffffffffffffff81111561145457611454611cb5565b60405190808252806020026020018201604052801561147d578160200160208202803683370190505b509050600080845111611491576000611497565b83516001015b855160010101905060008167ffffffffffffffff8111156114ba576114ba611cb5565b6040519080825280602002602001820160405280156114ed57816020015b60608152602001906001900390816114d85790505b5090506000611512604080516002815233602082015230818301526060810190915290565b828281518110611524576115246121aa565b602002602001018190525060005b8751811015611582578180600101925050878181518110611555576115556121aa565b602002602001015183838151811061156f5761156f6121aa565b6020908102919091010152600101611532565b50855115611732578080600101915050838282815181106115a5576115a56121aa565b602002602001018190525060005b8651811015611730576116648782815181106115d1576115d16121aa565b60200260200101516000015161164161160e8a85815181106115f5576115f56121aa565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b898481518110611653576116536121aa565b60200260200101516040015161182e565b61169d576040517f52bf9848000000000000000000000000000000000000000000000000000000008152600481018290526024016107e5565b8681815181106116af576116af6121aa565b6020026020010151600001516001600160a01b031660001b8582815181106116d9576116d96121aa565b60200260200101818152505081806001019250508681815181106116ff576116ff6121aa565b60200260200101516020015183838151811061171d5761171d6121aa565b60209081029190910101526001016115b3565b505b5095945050505050565b6060824710156117b45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107e5565b600080866001600160a01b031685876040516117d09190612a91565b60006040518083038185875af1925050503d806000811461180d576040519150601f19603f3d011682016040523d82523d6000602084013e611812565b606091505b50915091506118238783838761188f565b979650505050505050565b600080600061183d8585611908565b9092509050600081600481111561185657611856612aa3565b1480156118745750856001600160a01b0316826001600160a01b0316145b80611885575061188586868661194a565b9695505050505050565b606083156118fe5782516000036118f7576001600160a01b0385163b6118f75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107e5565b50816112f3565b6112f38383611a4f565b600080825160410361193e5760208301516040840151606085015160001a61193287828585611a79565b94509450505050610ce1565b50600090506002610ce1565b6000806000856001600160a01b0316631626ba7e60e01b8686604051602401611974929190612ab9565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516119b29190612a91565b600060405180830381855afa9150503d80600081146119ed576040519150601f19603f3d011682016040523d82523d6000602084013e6119f2565b606091505b5091509150818015611a0657506020815110155b8015611885575080517f1626ba7e0000000000000000000000000000000000000000000000000000000090611a449083016020908101908401612705565b149695505050505050565b815115611a5f5781518083602001fd5b8060405162461bcd60e51b81526004016107e59190612ad2565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611ab05750600090506003611b34565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611b04573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611b2d57600060019250925050611b34565b9150600090505b94509492505050565b600060208284031215611b4f57600080fd5b81356001600160e01b031981168114611b6757600080fd5b9392505050565b6001600160a01b0381168114611b8357600080fd5b50565b600080600060608486031215611b9b57600080fd5b8335611ba681611b6e565b9250602084013567ffffffffffffffff80821115611bc357600080fd5b9085019060a08288031215611bd757600080fd5b90925060408501359080821115611bed57600080fd5b50840160408187031215611c0057600080fd5b809150509250925092565b60008060008060008060a08789031215611c2457600080fd5b8635611c2f81611b6e565b95506020870135611c3f81611b6e565b94506040870135935060608701359250608087013567ffffffffffffffff80821115611c6a57600080fd5b818901915089601f830112611c7e57600080fd5b813581811115611c8d57600080fd5b8a6020828501011115611c9f57600080fd5b6020830194508093505050509295509295509295565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611cee57611cee611cb5565b60405290565b6040805190810167ffffffffffffffff81118282101715611cee57611cee611cb5565b604051601f8201601f1916810167ffffffffffffffff81118282101715611d4057611d40611cb5565b604052919050565b600082601f830112611d5957600080fd5b813567ffffffffffffffff811115611d7357611d73611cb5565b611d86601f8201601f1916602001611d17565b818152846020838601011115611d9b57600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115611dd257611dd2611cb5565b5060051b60200190565b600082601f830112611ded57600080fd5b81356020611e02611dfd83611db8565b611d17565b82815260059290921b84018101918181019086841115611e2157600080fd5b8286015b84811015611f2857803567ffffffffffffffff80821115611e4557600080fd5b908801906060828b03601f19011215611e5e5760008081fd5b611e66611ccb565b86830135611e7381611b6e565b815260408381013583811115611e895760008081fd5b8401603f81018d13611e9b5760008081fd5b88810135611eab611dfd82611db8565b81815260059190911b82018301908a8101908f831115611ecb5760008081fd5b928401925b82841015611ee95783358252928b0192908b0190611ed0565b858c0152505050606084013583811115611f035760008081fd5b611f118d8a83880101611d48565b918301919091525085525050918301918301611e25565b509695505050505050565b600060408236031215611f4557600080fd5b611f4d611cf4565b823567ffffffffffffffff80821115611f6557600080fd5b818501915060608236031215611f7a57600080fd5b611f82611ccb565b8235611f8d81611b6e565b81526020830135611f9d81611b6e565b6020820152604083013582811115611fb457600080fd5b611fc036828601611d48565b60408301525083526020850135915080821115611fdc57600080fd5b50611fe936828601611ddc565b60208301525092915050565b60005b83811015612010578181015183820152602001611ff8565b50506000910152565b60008151808452612031816020860160208601611ff5565b601f01601f19169290920160200192915050565b60008151808452602080850194506020840160005b838110156120765781518752958201959082019060010161205a565b509495945050505050565b6000602080835260608451604080848701526001600160a01b03808351166060880152808584015116608088015260408301519250606060a08801526120ca60c0880184612019565b85890151601f19898303810160408b015281518084529295509087019185880190600581901b8701890160005b8281101561214f578489830301845285518781511683528b8101518b8d8501526121238c850182612045565b918a0151848303858c015291905061213b8183612019565b978d0197958d0195935050506001016120f7565b509c9b505050505050505050505050565b6000808335601e1984360301811261217757600080fd5b83018035915067ffffffffffffffff82111561219257600080fd5b6020019150600581901b3603821315610ce157600080fd5b634e487b7160e01b600052603260045260246000fd5b60008235607e198336030181126121d657600080fd5b9190910192915050565b60008235609e198336030181126121d657600080fd5b6000808335601e1984360301811261220d57600080fd5b83018035915067ffffffffffffffff82111561222857600080fd5b6020019150600681901b3603821315610ce157600080fd5b60006020828403121561225257600080fd5b8135611b6781611b6e565b6000808335601e1984360301811261227457600080fd5b830160208101925035905067ffffffffffffffff81111561229457600080fd5b8060051b3603821315610ce157600080fd5b60008235605e198336030181126122bc57600080fd5b90910192915050565b6000808335601e198436030181126122dc57600080fd5b830160208101925035905067ffffffffffffffff8111156122fc57600080fd5b803603821315610ce157600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261234b57600080fd5b830160208101925035905067ffffffffffffffff81111561236b57600080fd5b8060061b3603821315610ce157600080fd5b8183526000602080850194508260005b858110156120765781356123a081611b6e565b6001600160a01b0316875281830135838801526040968701969091019060010161238d565b818352602080840193600091600585811b830182018585805b898110156124a057868403601f19018b526123f9838a6122a6565b6060813561240681611b6e565b6001600160a01b0316865261241d8289018361225d565b828a8901528083890152608092507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115612457578586fd5b881b808289850137870190506040612471848201856122c5565b94508389840301828a0152612489848401868361230b565b9f8b019f98505050948801945050506001016123de565b50919998505050505050505050565b6000602080835260c0830184358285015260408286013581860152606081870135818701526124e08188018861225d565b60a060808901528481865260e08901905060e08260051b8a010195508260005b83811015612662578a880360df19018352813536869003607e1901811261252657600080fd5b8501803536829003609e1901811261253d57600080fd5b60808a528101803561254e81611b6e565b6001600160a01b0380821660808d015261256a8d8401846122a6565b915060a0808d0152813561257d81611b6e565b81166101208d0152818d013561259281611b6e565b166101408c01526125a5818b01826122c5565b9150896101608d01526125bd6101808d01838361230b565b9150506125cc8a830183612334565b607f19808e85030160c08f01526125e484838561237d565b93506125f28c860186612334565b93509150808e85030160e08f01525061260c83838361237d565b9250505060808201356101008c01528b8301358c8c0152898301358a8c01526126378984018461225d565b935091508a8103898c015261264d8184846123c5565b9a505050928901925090880190600101612500565b5050505050505061267660808601866122c5565b858303601f190160a0870152925061188582848361230b565b600080604083850312156126a257600080fd5b505080516020909101519092909150565b6000602082840312156126c557600080fd5b815160ff81168114611b6757600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016126fe576126fe6126d6565b5060010190565b60006020828403121561271757600080fd5b5051919050565b60006020828403121561273057600080fd5b81518015158114611b6757600080fd5b60008282518085526020808601955060208260051b8401016020860160005b8481101561278d57601f1986840301895261277b838351612045565b9884019892509083019060010161275f565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201526000604083015160e060608401526127d4610100840182612019565b9050606084015160808401526080840151601f19808584030160a08601526127fc8383612740565b925060a08601519150808584030160c08601526128198383612045565b925060c08601519150808584030160e0860152506128378282612045565b95945050505050565b600082601f83011261285157600080fd5b81516020612861611dfd83611db8565b8083825260208201915060208460051b87010193508684111561288357600080fd5b602086015b84811015611f285780518352918301918301612888565b600080604083850312156128b257600080fd5b825167ffffffffffffffff808211156128ca57600080fd5b818501915085601f8301126128de57600080fd5b815160206128ee611dfd83611db8565b82815260059290921b8401810191818101908984111561290d57600080fd5b948201945b8386101561292b57855182529482019490820190612912565b9188015191965090935050508082111561294457600080fd5b5061295185828601612840565b9150509250929050565b8281526040602082015260006112f36040830184612045565b634e487b7160e01b600052601260045260246000fd5b600181815b808511156129c55781600019048211156129ab576129ab6126d6565b808516156129b857918102915b93841c939080029061298f565b509250929050565b6000826129dc575060016101f5565b816129e9575060006101f5565b81600181146129ff5760028114612a0957612a25565b60019150506101f5565b60ff841115612a1a57612a1a6126d6565b50506001821b6101f5565b5060208310610133831016604e8410600b8410161715612a48575081810a6101f5565b612a52838361298a565b8060001904821115612a6657612a666126d6565b029392505050565b6000611b6783836129cd565b80820281158282048414176101f5576101f56126d6565b600082516121d6818460208701611ff5565b634e487b7160e01b600052602160045260246000fd5b8281526040602082015260006112f36040830184612019565b602081526000611b67602083018461201956","sourceMap":"1013:1794:126:-:0;;;1620:1:121;1583:38;;1212:230:126;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1285:6;2722::122;1716:1:51;1821:7;:22;;;;1750:29:121;1760:10;1772:6;1750:29;;;;;;;:::i;:::-;;;;;;;;1794:11;;;;:21;:30;;;:37;:42;1790:119;;1885:11;;;;;1874:23;;;;;;:::i;:::-;;;;-1:-1:-1;;1874:23:121;;;;;;;;;1864:34;;1874:23;1864:34;;;;1852:46;;1790:119;1628:287;2653:79:122;1304:22:126::1;1341:6;:25;;;1330:48;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;1388:47:126::1;;::::0;-1:-1:-1;1013:1794:126;;-1:-1:-1;1013:1794:126;14:127:141;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:253;218:2;212:9;260:4;248:17;;-1:-1:-1;;;;;280:34:141;;316:22;;;277:62;274:88;;;342:18;;:::i;:::-;378:2;371:22;146:253;:::o;404:257::-;476:4;470:11;;;508:17;;-1:-1:-1;;;;;540:34:141;;576:22;;;537:62;534:88;;;602:18;;:::i;666:275::-;737:2;731:9;802:2;783:13;;-1:-1:-1;;779:27:141;767:40;;-1:-1:-1;;;;;822:34:141;;858:22;;;819:62;816:88;;;884:18;;:::i;:::-;920:2;913:22;666:275;;-1:-1:-1;666:275:141:o;946:131::-;-1:-1:-1;;;;;1021:31:141;;1011:42;;1001:70;;1067:1;1064;1057:12;1001:70;946:131;:::o;1082:250::-;1167:1;1177:113;1191:6;1188:1;1185:13;1177:113;;;1267:11;;;1261:18;1248:11;;;1241:39;1213:2;1206:10;1177:113;;;-1:-1:-1;;1324:1:141;1306:16;;1299:27;1082:250::o;1337:509::-;1390:5;1443:3;1436:4;1428:6;1424:17;1420:27;1410:55;;1461:1;1458;1451:12;1410:55;1484:13;;-1:-1:-1;;;;;1509:26:141;;1506:52;;;1538:18;;:::i;:::-;1582:55;1625:2;1606:13;;-1:-1:-1;;1602:27:141;1631:4;1598:38;1582:55;:::i;:::-;1662:2;1653:7;1646:19;1708:3;1701:4;1696:2;1688:6;1684:15;1680:26;1677:35;1674:55;;;1725:1;1722;1715:12;1674:55;1738:77;1812:2;1805:4;1796:7;1792:18;1785:4;1777:6;1773:17;1738:77;:::i;:::-;1833:7;1337:509;-1:-1:-1;;;;1337:509:141:o;1851:198::-;1926:4;-1:-1:-1;;;;;1948:30:141;;1945:56;;;1981:18;;:::i;:::-;-1:-1:-1;2026:1:141;2022:14;2038:4;2018:25;;1851:198::o;2054:2494::-;2134:5;2187:3;2180:4;2172:6;2168:17;2164:27;2154:55;;2205:1;2202;2195:12;2154:55;2234:6;2228:13;2260:4;2284:75;2300:58;2355:2;2300:58;:::i;:::-;2284:75;:::i;:::-;2393:15;;;2479:1;2475:10;;;;2463:23;;2459:32;;;2424:12;;;;2503:15;;;2500:35;;;2531:1;2528;2521:12;2500:35;2567:2;2559:6;2555:15;2579:1940;2595:6;2590:3;2587:15;2579:1940;;;2668:10;;-1:-1:-1;;;;;2735:19:141;;;2732:39;;;2767:1;2764;2757:12;2732:39;2794:24;;;;2866:4;2842:12;;;-1:-1:-1;;2838:26:141;2834:37;2831:127;;;2912:1;2941:2;2937;2930:14;2831:127;2984:22;;:::i;:::-;3048:2;3044;3040:11;3034:18;3065:33;3090:7;3065:33;:::i;:::-;3111:22;;3156:2;3193:11;;;3187:18;3221:16;;;3218:106;;;3278:1;3307:2;3303;3296:14;3218:106;3347:17;;3399:2;3391:11;;3387:21;-1:-1:-1;3377:119:141;;3450:1;3479:2;3475;3468:14;3377:119;3534:2;3530;3526:11;3520:18;3564:76;3580:59;3635:3;3580:59;:::i;3564:76::-;3684:18;;;3783:1;3779:11;;;;3771:20;;3767:29;;;3724:14;;;;3812:17;;;3809:110;;;3871:1;3901:3;3896;3889:16;3809:110;3945:11;;;;3969:167;3987:8;3980:5;3977:19;3969:167;;;4069:12;;4055:27;;4008:14;;;;4108;;;;3969:167;;;4156:14;;;4149:29;-1:-1:-1;;;4221:4:141;4213:13;;4207:20;4243:16;;;4240:109;;;4301:1;4331:3;4326;4319:16;4240:109;4385:60;4441:3;4436:2;4425:8;4421:2;4417:17;4413:26;4385:60;:::i;:::-;4369:14;;;4362:84;;;;-1:-1:-1;4459:18:141;;-1:-1:-1;;4497:12:141;;;;2612;;2579:1940;;;-1:-1:-1;4537:5:141;2054:2494;-1:-1:-1;;;;;;2054:2494:141:o;4553:1916::-;4662:6;4693:2;4736;4724:9;4715:7;4711:23;4707:32;4704:52;;;4752:1;4749;4742:12;4704:52;4779:16;;-1:-1:-1;;;;;4844:14:141;;;4841:34;;;4871:1;4868;4861:12;4841:34;4894:22;;;;4950:4;4932:16;;;4928:27;4925:47;;;4968:1;4965;4958:12;4925:47;4994:22;;:::i;:::-;5046:2;5040:9;5058:33;5083:7;5058:33;:::i;:::-;5100:22;;5153:11;;;5147:18;5177:16;;;5174:36;;;5206:1;5203;5196:12;5174:36;5229:17;;5280:4;5262:16;;;5258:27;5255:47;;;5298:1;5295;5288:12;5255:47;5326:22;;:::i;:::-;5379:2;5373:9;5407:2;5397:8;5394:16;5391:36;;;5423:1;5420;5413:12;5391:36;5446:17;;5497:4;5479:16;;;5475:27;5472:47;;;5515:1;5512;5505:12;5472:47;5543:22;;:::i;:::-;5595:2;5589:9;5607:33;5632:7;5607:33;:::i;:::-;5649:24;;5703:11;;;5697:18;5724:33;5697:18;5724:33;:::i;:::-;5773:16;;;5766:33;5838:4;5830:13;;5824:20;5856:16;;;5853:36;;;5885:1;5882;5875:12;5853:36;5925:55;5972:7;5961:8;5957:2;5953:17;5925:55;:::i;:::-;5918:4;5905:18;;5898:83;-1:-1:-1;5990:24:141;;-1:-1:-1;6045:11:141;;;6039:18;6069:16;;;6066:36;;;6098:1;6095;6088:12;6066:36;6136:82;6210:7;6199:8;6195:2;6191:17;6136:82;:::i;:::-;6131:2;6122:7;6118:16;6111:108;;6251:7;6246:2;6239:5;6235:14;6228:31;;;6298:4;6294:2;6290:13;6284:20;6268:36;;6329:2;6319:8;6316:16;6313:36;;;6345:1;6342;6335:12;6313:36;6383:55;6430:7;6419:8;6415:2;6411:17;6383:55;:::i;:::-;6376:4;6365:16;;6358:81;6369:5;4553:1916;-1:-1:-1;;;;;;4553:1916:141:o;6474:270::-;6515:3;6553:5;6547:12;6580:6;6575:3;6568:19;6596:76;6665:6;6658:4;6653:3;6649:14;6642:4;6635:5;6631:16;6596:76;:::i;:::-;6726:2;6705:15;-1:-1:-1;;6701:29:141;6692:39;;;;6733:4;6688:50;;6474:270;-1:-1:-1;;6474:270:141:o;6749:2011::-;6798:3;6826:4;6865:5;6859:12;6892:4;6887:3;6880:17;6933:1;6929;6924:3;6920:11;6916:19;6992:2;6977:12;6971:19;6967:28;6960:4;6955:3;6951:14;6944:52;7015:4;7074:2;7060:12;7056:21;7050:28;7097:4;7153:2;7137:14;7133:23;7126:4;7121:3;7117:14;7110:47;7212:4;7198:12;7194:23;7188:30;7166:52;;7249:4;7243:3;7238;7234:13;7227:27;7276:47;7318:3;7313;7309:13;7293:14;7276:47;:::i;:::-;7360:14;;;7354:21;7405:15;;;7391:12;;;7384:37;7471:21;;7501;;;7263:60;;-1:-1:-1;7633:23:141;;;-1:-1:-1;7540:14:141;;;;7594:1;7590:14;;;7579:26;;7575:35;;7674:1;;7705:1029;7721:6;7716:3;7713:15;7705:1029;;;7792:16;;;-1:-1:-1;;7788:30:141;7774:45;;7842:13;;7925:9;;7921:18;;7908:32;;7981:11;;;7975:18;8013:13;;;8006:25;;;8092:21;;7882:13;;;8126:24;;;8215:23;;;;8262:1;;8182:3;8172:14;;;8276:209;8292:8;8287:3;8284:17;8276:209;;;8369:15;;8355:30;;8454:17;;;;8320:1;8311:11;;;;;8411:14;;;;8276:209;;;8280:3;8534:2;8530;8526:11;8520:18;8498:40;;8584:4;8577:5;8573:16;8568:2;8562:4;8558:13;8551:39;8611;8644:5;8628:14;8611:39;:::i;:::-;8603:47;;;;;;8685:2;8677:6;8673:15;8663:25;;8721:2;8714:5;8710:14;8701:23;;7747:1;7742:3;7738:11;7731:18;;7705:1029;;;-1:-1:-1;8750:4:141;;6749:2011;-1:-1:-1;;;;;;;;;;;;6749:2011:141:o;8765:753::-;-1:-1:-1;;;;;9038:15:141;;;9020:34;;9090:2;9085;9070:18;;;9063:30;;;9133:13;;9129:22;;;9109:18;;;9102:50;9187:15;;9181:22;9241:4;9219:20;;;9212:34;8963:4;;9269:59;9000:3;9308:19;;9181:22;9269:59;:::i;:::-;9255:73;;9377:2;9369:6;9365:15;9359:22;9450:2;9446:7;9434:9;9426:6;9422:22;9418:36;9412:3;9401:9;9397:19;9390:65;9472:40;9505:6;9489:14;9472:40;:::i;:::-;9464:48;8765:753;-1:-1:-1;;;;;;8765:753:141:o;9523:257::-;9702:2;9691:9;9684:21;9665:4;9722:52;9770:2;9759:9;9755:18;9747:6;9722:52;:::i;:::-;9714:60;9523:257;-1:-1:-1;;;9523:257:141:o;9785:259::-;9863:6;9916:2;9904:9;9895:7;9891:23;9887:32;9884:52;;;9932:1;9929;9922:12;9884:52;9964:9;9958:16;9983:31;10008:5;9983:31;:::i;9785:259::-;1013:1794:126;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x60806040526004361061005a5760003560e01c8063691f9ed711610043578063691f9ed7146100b057806393be095e146100d0578063b8757e06146101125761005a565b806301ffc9a7146100685780634ed394611461009d575b34801561006657600080fd5b005b34801561007457600080fd5b50610088610083366004611b3d565b61015e565b60405190151581526020015b60405180910390f35b6100666100ab366004611b86565b6101fb565b3480156100bc57600080fd5b506100666100cb366004611c0b565b610539565b3480156100dc57600080fd5b506101047f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610094565b34801561011e57600080fd5b506101467f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610094565b60006001600160e01b031982167f691f9ed70000000000000000000000000000000000000000000000000000000014806101c157506001600160e01b031982167f4ed3946100000000000000000000000000000000000000000000000000000000145b806101f557507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b610203610797565b61020c81611f33565b7f0000000000000000000000000000000000000000000000000000000000000000158015906102815750806040516020016102479190612081565b604051602081830303815290604052805190602001207f000000000000000000000000000000000000000000000000000000000000000014155b156102b8576040517f8812562900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102c56060840184612160565b9050600003610300576040517f9c95219f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061030f6060850185612160565b6000818110610320576103206121aa565b905060200281019061033291906121c0565b61033c90806121e0565b61034a9060408101906121f6565b6103576060870187612160565b6000818110610368576103686121aa565b905060200281019061037a91906121c0565b6020013581811061038d5761038d6121aa565b6103a39260206040909202019081019150612240565b905060006103b46060860186612160565b60008181106103c5576103c56121aa565b90506020028101906103d791906121c0565b6103e190806121e0565b6103ef9060608101906121f6565b6103fc6060880188612160565b600081811061040d5761040d6121aa565b905060200281019061041f91906121c0565b60400135818110610432576104326121aa565b6104489260206040909202019081019150612240565b905061045f6001600160a01b0383168760006107f5565b6104756001600160a01b038316876000196107f5565b600080876001600160a01b031663d0f7a862886040518263ffffffff1660e01b81526004016104a491906124af565b60408051808303816000875af11580156104c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e6919061268f565b90925090506105006001600160a01b0385168960006107f5565b61052561050c87611f33565b8561051687610976565b8661052088610976565b610a10565b50505050506105346001600055565b505050565b61056e6001600160a01b0387167f000000000000000000000000000000000000000000000000000000000000000060006107f5565b6105a46001600160a01b0387167f00000000000000000000000000000000000000000000000000000000000000006000196107f5565b60006105b282840184612240565b9050600080610622878a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061d91906126b3565b610cba565b9150915060008061066b888b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105f9573d6000803e3d6000fd5b9150915080610682578161067e816126ec565b9250505b6040517f9d73b3250000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301528c811660248301528b81166044830152606482018690526084820184905260001960a48301526000917f000000000000000000000000000000000000000000000000000000000000000090911690639d73b3259060c4016020604051808303816000875af115801561072e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107529190612705565b90506107896001600160a01b038d167f000000000000000000000000000000000000000000000000000000000000000060006107f5565b505050505050505050505050565b6002600054036107ee5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b6002600055565b80158061088857506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015610862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108869190612705565b155b6108fa5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084016107e5565b6040516001600160a01b0383166024820152604481018290526105349084907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610ce8565b6040517f54636d2b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152600090734f1c29faab7eddf8d7794695d8259996734cc665906354636d2b906024016020604051808303816000875af11580156109ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f591906126b3565b604080516001808252818301909252600091816020015b6060815260200190600190039081610a27575050604080516003808252608082019092529192506000919060208201606080368337019050506040516370a0823160e01b81523060048201529091506000906001600160a01b038816906370a0823190602401602060405180830381865afa158015610aaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ace9190612705565b90508015610aea57610aea6001600160a01b0388163383610dd0565b600080610af78389610e19565b915091508184600081518110610b0f57610b0f6121aa565b602090810291909101015250506040516370a0823160e01b8152306004820152600091506001600160a01b038616906370a0823190602401602060405180830381865afa158015610b64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b889190612705565b90508015610ba457610ba46001600160a01b0386163383610dd0565b600080610bb18387610e19565b915091508184600181518110610bc957610bc96121aa565b602090810291909101015250479150610be490503382610e5d565b610bf081601119610f76565b82600281518110610c0357610c036121aa565b602002602001018181525050508082600081518110610c2457610c246121aa565b6020908102919091010152604080516001808252818301909252600091816020015b6040805160a08101825260009181018281526060808301939093526080820183905281526020810191909152815260200190600190039081610c465790505090508781600081518110610c9b57610c9b6121aa565b6020026020010181905250610cb08382610fd2565b5050505050505050565b6000806001600160e01b038416601b0b60e085901d610cda8282876111c3565b9350935050505b9250929050565b6000610d3d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166112e49092919063ffffffff16565b9050805160001480610d5e575080806020019051810190610d5e919061271e565b6105345760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107e5565b6040516001600160a01b0383166024820152604481018290526105349084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161093f565b6000806000806000610e2b87876112fb565b925092509250600080610e3e8585611359565b9150915081838015610e4d5750815b9650965050505050509250929050565b80471015610ead5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016107e5565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610efa576040519150601f19603f3d011682016040523d82523d6000602084013e610eff565b606091505b50509050806105345760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016107e5565b6000806000610f858585611359565b9150915080610fca576040517f22c9f7bb00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044016107e5565b509392505050565b3360008181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b8651811015610cb05786818151811061103a5761103a6121aa565b6020026020010151935060008460000151604001515111156111bb576000808560000151600001516001600160a01b031663d04dfe236040518060e001604052808960000151602001516001600160a01b031681526020018a81526020018960000151604001518152602001600081526020016110bb8e8b60200151611436565b8152602001888152602001878152506040518263ffffffff1660e01b81526004016110e6919061279a565b600060405180830381865afa158015611103573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261112b919081019061289f565b80519193509150156111b8578551602001516040517f04b19db40000000000000000000000000000000000000000000000000000000081526001600160a01b03909116906304b19db490611185908b90859060040161295b565b600060405180830381600087803b15801561119f57600080fd5b505af11580156111b3573d6000803e3d6000fd5b505050505b50505b60010161101f565b600080600085121561120b576040517f4a7d166b00000000000000000000000000000000000000000000000000000000815260048101869052602481018590526044016107e5565b8460000361121f57506000905060016112dc565b8460ff84168501858112156112515760405163d556b11160e01b815260048101889052602481018790526044016107e5565b60008060008312156112a157604c198312156112775760008095509550505050506112dc565b82600003600a0a915081848161128f5761128f612974565b04955050840290911491506112dc9050565b60008313156112d1576112b583600a612a6e565b91506112c18285612a7a565b9550600194506112dc9350505050565b509193506001925050505b935093915050565b60606112f3848460008561173c565b949350505050565b6000808060ff841681037f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86111561134857600a860460018201600a880660001493509350935050611352565b8593509150600190505b9250925092565b6000601b83900b83148383826113be577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561139e57620186a0860595506005850194505b8586601b0b146113b957600a8605955084600101945061139e565b6113d6565b856000036113d657506000925060019150610ce19050565b848560030b1461141b5760008512156113f8575060009250829150610ce19050565b60405163d556b11160e01b815260048101839052602481018290526044016107e5565b50506001600160e01b03841660e084901b1791509250929050565b60606000825167ffffffffffffffff81111561145457611454611cb5565b60405190808252806020026020018201604052801561147d578160200160208202803683370190505b509050600080845111611491576000611497565b83516001015b855160010101905060008167ffffffffffffffff8111156114ba576114ba611cb5565b6040519080825280602002602001820160405280156114ed57816020015b60608152602001906001900390816114d85790505b5090506000611512604080516002815233602082015230818301526060810190915290565b828281518110611524576115246121aa565b602002602001018190525060005b8751811015611582578180600101925050878181518110611555576115556121aa565b602002602001015183838151811061156f5761156f6121aa565b6020908102919091010152600101611532565b50855115611732578080600101915050838282815181106115a5576115a56121aa565b602002602001018190525060005b8651811015611730576116648782815181106115d1576115d16121aa565b60200260200101516000015161164161160e8a85815181106115f5576115f56121aa565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b898481518110611653576116536121aa565b60200260200101516040015161182e565b61169d576040517f52bf9848000000000000000000000000000000000000000000000000000000008152600481018290526024016107e5565b8681815181106116af576116af6121aa565b6020026020010151600001516001600160a01b031660001b8582815181106116d9576116d96121aa565b60200260200101818152505081806001019250508681815181106116ff576116ff6121aa565b60200260200101516020015183838151811061171d5761171d6121aa565b60209081029190910101526001016115b3565b505b5095945050505050565b6060824710156117b45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107e5565b600080866001600160a01b031685876040516117d09190612a91565b60006040518083038185875af1925050503d806000811461180d576040519150601f19603f3d011682016040523d82523d6000602084013e611812565b606091505b50915091506118238783838761188f565b979650505050505050565b600080600061183d8585611908565b9092509050600081600481111561185657611856612aa3565b1480156118745750856001600160a01b0316826001600160a01b0316145b80611885575061188586868661194a565b9695505050505050565b606083156118fe5782516000036118f7576001600160a01b0385163b6118f75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107e5565b50816112f3565b6112f38383611a4f565b600080825160410361193e5760208301516040840151606085015160001a61193287828585611a79565b94509450505050610ce1565b50600090506002610ce1565b6000806000856001600160a01b0316631626ba7e60e01b8686604051602401611974929190612ab9565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516119b29190612a91565b600060405180830381855afa9150503d80600081146119ed576040519150601f19603f3d011682016040523d82523d6000602084013e6119f2565b606091505b5091509150818015611a0657506020815110155b8015611885575080517f1626ba7e0000000000000000000000000000000000000000000000000000000090611a449083016020908101908401612705565b149695505050505050565b815115611a5f5781518083602001fd5b8060405162461bcd60e51b81526004016107e59190612ad2565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611ab05750600090506003611b34565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611b04573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611b2d57600060019250925050611b34565b9150600090505b94509492505050565b600060208284031215611b4f57600080fd5b81356001600160e01b031981168114611b6757600080fd5b9392505050565b6001600160a01b0381168114611b8357600080fd5b50565b600080600060608486031215611b9b57600080fd5b8335611ba681611b6e565b9250602084013567ffffffffffffffff80821115611bc357600080fd5b9085019060a08288031215611bd757600080fd5b90925060408501359080821115611bed57600080fd5b50840160408187031215611c0057600080fd5b809150509250925092565b60008060008060008060a08789031215611c2457600080fd5b8635611c2f81611b6e565b95506020870135611c3f81611b6e565b94506040870135935060608701359250608087013567ffffffffffffffff80821115611c6a57600080fd5b818901915089601f830112611c7e57600080fd5b813581811115611c8d57600080fd5b8a6020828501011115611c9f57600080fd5b6020830194508093505050509295509295509295565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611cee57611cee611cb5565b60405290565b6040805190810167ffffffffffffffff81118282101715611cee57611cee611cb5565b604051601f8201601f1916810167ffffffffffffffff81118282101715611d4057611d40611cb5565b604052919050565b600082601f830112611d5957600080fd5b813567ffffffffffffffff811115611d7357611d73611cb5565b611d86601f8201601f1916602001611d17565b818152846020838601011115611d9b57600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115611dd257611dd2611cb5565b5060051b60200190565b600082601f830112611ded57600080fd5b81356020611e02611dfd83611db8565b611d17565b82815260059290921b84018101918181019086841115611e2157600080fd5b8286015b84811015611f2857803567ffffffffffffffff80821115611e4557600080fd5b908801906060828b03601f19011215611e5e5760008081fd5b611e66611ccb565b86830135611e7381611b6e565b815260408381013583811115611e895760008081fd5b8401603f81018d13611e9b5760008081fd5b88810135611eab611dfd82611db8565b81815260059190911b82018301908a8101908f831115611ecb5760008081fd5b928401925b82841015611ee95783358252928b0192908b0190611ed0565b858c0152505050606084013583811115611f035760008081fd5b611f118d8a83880101611d48565b918301919091525085525050918301918301611e25565b509695505050505050565b600060408236031215611f4557600080fd5b611f4d611cf4565b823567ffffffffffffffff80821115611f6557600080fd5b818501915060608236031215611f7a57600080fd5b611f82611ccb565b8235611f8d81611b6e565b81526020830135611f9d81611b6e565b6020820152604083013582811115611fb457600080fd5b611fc036828601611d48565b60408301525083526020850135915080821115611fdc57600080fd5b50611fe936828601611ddc565b60208301525092915050565b60005b83811015612010578181015183820152602001611ff8565b50506000910152565b60008151808452612031816020860160208601611ff5565b601f01601f19169290920160200192915050565b60008151808452602080850194506020840160005b838110156120765781518752958201959082019060010161205a565b509495945050505050565b6000602080835260608451604080848701526001600160a01b03808351166060880152808584015116608088015260408301519250606060a08801526120ca60c0880184612019565b85890151601f19898303810160408b015281518084529295509087019185880190600581901b8701890160005b8281101561214f578489830301845285518781511683528b8101518b8d8501526121238c850182612045565b918a0151848303858c015291905061213b8183612019565b978d0197958d0195935050506001016120f7565b509c9b505050505050505050505050565b6000808335601e1984360301811261217757600080fd5b83018035915067ffffffffffffffff82111561219257600080fd5b6020019150600581901b3603821315610ce157600080fd5b634e487b7160e01b600052603260045260246000fd5b60008235607e198336030181126121d657600080fd5b9190910192915050565b60008235609e198336030181126121d657600080fd5b6000808335601e1984360301811261220d57600080fd5b83018035915067ffffffffffffffff82111561222857600080fd5b6020019150600681901b3603821315610ce157600080fd5b60006020828403121561225257600080fd5b8135611b6781611b6e565b6000808335601e1984360301811261227457600080fd5b830160208101925035905067ffffffffffffffff81111561229457600080fd5b8060051b3603821315610ce157600080fd5b60008235605e198336030181126122bc57600080fd5b90910192915050565b6000808335601e198436030181126122dc57600080fd5b830160208101925035905067ffffffffffffffff8111156122fc57600080fd5b803603821315610ce157600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261234b57600080fd5b830160208101925035905067ffffffffffffffff81111561236b57600080fd5b8060061b3603821315610ce157600080fd5b8183526000602080850194508260005b858110156120765781356123a081611b6e565b6001600160a01b0316875281830135838801526040968701969091019060010161238d565b818352602080840193600091600585811b830182018585805b898110156124a057868403601f19018b526123f9838a6122a6565b6060813561240681611b6e565b6001600160a01b0316865261241d8289018361225d565b828a8901528083890152608092507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115612457578586fd5b881b808289850137870190506040612471848201856122c5565b94508389840301828a0152612489848401868361230b565b9f8b019f98505050948801945050506001016123de565b50919998505050505050505050565b6000602080835260c0830184358285015260408286013581860152606081870135818701526124e08188018861225d565b60a060808901528481865260e08901905060e08260051b8a010195508260005b83811015612662578a880360df19018352813536869003607e1901811261252657600080fd5b8501803536829003609e1901811261253d57600080fd5b60808a528101803561254e81611b6e565b6001600160a01b0380821660808d015261256a8d8401846122a6565b915060a0808d0152813561257d81611b6e565b81166101208d0152818d013561259281611b6e565b166101408c01526125a5818b01826122c5565b9150896101608d01526125bd6101808d01838361230b565b9150506125cc8a830183612334565b607f19808e85030160c08f01526125e484838561237d565b93506125f28c860186612334565b93509150808e85030160e08f01525061260c83838361237d565b9250505060808201356101008c01528b8301358c8c0152898301358a8c01526126378984018461225d565b935091508a8103898c015261264d8184846123c5565b9a505050928901925090880190600101612500565b5050505050505061267660808601866122c5565b858303601f190160a0870152925061188582848361230b565b600080604083850312156126a257600080fd5b505080516020909101519092909150565b6000602082840312156126c557600080fd5b815160ff81168114611b6757600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016126fe576126fe6126d6565b5060010190565b60006020828403121561271757600080fd5b5051919050565b60006020828403121561273057600080fd5b81518015158114611b6757600080fd5b60008282518085526020808601955060208260051b8401016020860160005b8481101561278d57601f1986840301895261277b838351612045565b9884019892509083019060010161275f565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201526000604083015160e060608401526127d4610100840182612019565b9050606084015160808401526080840151601f19808584030160a08601526127fc8383612740565b925060a08601519150808584030160c08601526128198383612045565b925060c08601519150808584030160e0860152506128378282612045565b95945050505050565b600082601f83011261285157600080fd5b81516020612861611dfd83611db8565b8083825260208201915060208460051b87010193508684111561288357600080fd5b602086015b84811015611f285780518352918301918301612888565b600080604083850312156128b257600080fd5b825167ffffffffffffffff808211156128ca57600080fd5b818501915085601f8301126128de57600080fd5b815160206128ee611dfd83611db8565b82815260059290921b8401810191818101908984111561290d57600080fd5b948201945b8386101561292b57855182529482019490820190612912565b9188015191965090935050508082111561294457600080fd5b5061295185828601612840565b9150509250929050565b8281526040602082015260006112f36040830184612045565b634e487b7160e01b600052601260045260246000fd5b600181815b808511156129c55781600019048211156129ab576129ab6126d6565b808516156129b857918102915b93841c939080029061298f565b509250929050565b6000826129dc575060016101f5565b816129e9575060006101f5565b81600181146129ff5760028114612a0957612a25565b60019150506101f5565b60ff841115612a1a57612a1a6126d6565b50506001821b6101f5565b5060208310610133831016604e8410600b8410161715612a48575081810a6101f5565b612a52838361298a565b8060001904821115612a6657612a666126d6565b029392505050565b6000611b6783836129cd565b80820281158282048414176101f5576101f56126d6565b600082516121d6818460208701611ff5565b634e487b7160e01b600052602160045260246000fd5b8281526040602082015260006112f36040830184612019565b602081526000611b67602083018461201956","sourceMap":"1013:1794:126:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2766:288:122;;;;;;;;;;-1:-1:-1;2766:288:122;;;;;:::i;:::-;;:::i;:::-;;;516:14:141;;509:22;491:41;;479:2;464:18;2766:288:122;;;;;;;;3106:1220;;;;;;:::i;:::-;;:::i;1493:1255:126:-;;;;;;;;;;-1:-1:-1;1493:1255:126;;;;;:::i;:::-;;:::i;1583:38:121:-;;;;;;;;;;;;;;;;;;2814:25:141;;;2802:2;2787:18;1583:38:121;2668:177:141;1159:46:126;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3038:55:141;;;3020:74;;3008:2;2993:18;1159:46:126;2850:250:141;2766:288:122;2851:4;-1:-1:-1;;;;;;2875:55:122;;2890:40;2875:55;;2874:133;;-1:-1:-1;;;;;;;2948:58:122;;2963:43;2948:58;2874:133;:173;;;-1:-1:-1;952:25:63;-1:-1:-1;;;;;;937:40:63;;;3011:36:122;2867:180;2766:288;-1:-1:-1;;2766:288:122:o;3106:1220::-;2261:21:51;:19;:21::i;:::-;1921:186:121::1;3282:4:122::0;1921:186:121::1;:::i;:::-;1978:9;:23:::0;;::::1;::::0;:67:::1;;;2039:4;2028:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;2018:27;;;;;;2005:9;:40;;1978:67;1974:116;;;2068:11;;;;;;;;;;;;;;1974:116;3375:17:122::2;;::::0;::::2;:10:::0;:17:::2;:::i;:::-;:24;;3403:1;3375:29:::0;3371:77:::2;;3427:10;;;;;;;;;;;;;;3371:77;3458:24;3485:17;;::::0;::::2;:10:::0;:17:::2;:::i;:::-;3503:1;3485:20;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:26;::::0;;::::2;:::i;:::-;:38;::::0;::::2;::::0;::::2;::::0;::::2;:::i;:::-;3524:17;;::::0;::::2;:10:::0;:17:::2;:::i;:::-;3542:1;3524:20;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:33;;;3485:73;;;;;;;:::i;:::-;:79;::::0;::::2;:73;::::0;;::::2;;:79:::0;;::::2;::::0;-1:-1:-1;3485:79:122::2;:::i;:::-;3458:106:::0;-1:-1:-1;3574:25:122::2;3602:17;;::::0;::::2;:10:::0;:17:::2;:::i;:::-;3620:1;3602:20;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:26;::::0;;::::2;:::i;:::-;:39;::::0;::::2;::::0;::::2;::::0;::::2;:::i;:::-;3642:17;;::::0;::::2;:10:::0;:17:::2;:::i;:::-;3660:1;3642:20;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:34;;;3602:75;;;;;;;:::i;:::-;:81;::::0;::::2;:75;::::0;;::::2;;:81:::0;;::::2;::::0;-1:-1:-1;3602:81:122::2;:::i;:::-;3574:109:::0;-1:-1:-1;3694:59:122::2;-1:-1:-1::0;;;;;3694:36:122;::::2;3739:9:::0;3751:1:::2;3694:36;:59::i;:::-;3763:75;-1:-1:-1::0;;;;;3763:36:122;::::2;3808:9:::0;-1:-1:-1;;3763:36:122::2;:75::i;:::-;3849:21;3872:22:::0;3898:9:::2;-1:-1:-1::0;;;;;3898:21:122::2;;3920:10;3898:33;;;;;;;;;;;;;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3848:83:::0;;-1:-1:-1;3848:83:122;-1:-1:-1;3986:59:122::2;-1:-1:-1::0;;;;;3986:36:122;::::2;4031:9:::0;4043:1:::2;3986:36;:59::i;:::-;4056:263;;4097:4:::0;4056:263:::2;:::i;:::-;4115:16;4145:59;4187:16;4145:41;:59::i;:::-;4218:17;4249:60;4291:17;4249:41;:60::i;:::-;4056:27;:263::i;:::-;3292:1034;;;;2292:1:51::1;2303:20:::0;1716:1;2809:7;:22;2629:209;2303:20;3106:1220:122;;;:::o;1493:1255:126:-;1822:58;-1:-1:-1;;;;;1822:30:126;;1861:14;1878:1;1822:30;:58::i;:::-;1890:74;-1:-1:-1;;;;;1890:30:126;;1929:14;-1:-1:-1;;1890:30:126;:74::i;:::-;1974:28;2005:37;;;;2016:14;2005:37;:::i;:::-;1974:68;;2053:24;2079;2119:91;2155:15;2187:10;-1:-1:-1;;;;;2172:35:126;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2119:35;:91::i;:::-;2052:158;;;;2252:25;2279:13;2308:94;2344:17;2378:11;-1:-1:-1;;;;;2363:36:126;;:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2308:94;2251:151;;;;2417:8;2412:59;;2441:19;;;;:::i;:::-;;;;2412:59;2502:150;;;;;-1:-1:-1;;;;;23745:15:141;;;2502:150:126;;;23727:34:141;23797:15;;;23777:18;;;23770:43;23849:15;;;23829:18;;;23822:43;23881:18;;;23874:34;;;23924:19;;;23917:35;;;-1:-1:-1;;23968:19:141;;;23961:35;-1:-1:-1;;2502:14:126;:25;;;;;;23638:19:141;;2502:150:126;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2480:172;-1:-1:-1;2662:58:126;-1:-1:-1;;;;;2662:30:126;;2701:14;2718:1;2662:30;:58::i;:::-;1706:1042;;;;;;1493:1255;;;;;;:::o;2336:287:51:-;1759:1;2468:7;;:19;2460:63;;;;-1:-1:-1;;;2460:63:51;;24398:2:141;2460:63:51;;;24380:21:141;24437:2;24417:18;;;24410:30;24476:33;24456:18;;;24449:61;24527:18;;2460:63:51;;;;;;;;;1759:1;2598:7;:18;2336:287::o;1818:573:56:-;2143:10;;;2142:62;;-1:-1:-1;2159:39:56;;;;;2183:4;2159:39;;;24791:34:141;-1:-1:-1;;;;;24861:15:141;;;24841:18;;;24834:43;2159:15:56;;;;;24703:18:141;;2159:39:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;2142:62;2121:163;;;;-1:-1:-1;;;2121:163:56;;25090:2:141;2121:163:56;;;25072:21:141;25129:2;25109:18;;;25102:30;25168:34;25148:18;;;25141:62;25239:24;25219:18;;;25212:52;25281:19;;2121:163:56;24888:418:141;2121:163:56;2321:62;;-1:-1:-1;;;;;25503:55:141;;2321:62:56;;;25485:74:141;25575:18;;;25568:34;;;2294:90:56;;2314:5;;2344:22;;25458:18:141;;2321:62:56;;;;-1:-1:-1;;2321:62:56;;;;;;;;;;;;;;-1:-1:-1;;;;;2321:62:56;-1:-1:-1;;;;;;2321:62:56;;;;;;;;;;2294:19;:90::i;1465:146:117:-;1552:52;;;;;-1:-1:-1;;;;;3038:55:141;;1552:52:117;;;3020:74:141;1528:5:117;;1080:42;;1552:45;;2993:18:141;;1552:52:117;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;1049:2082:132:-;1280:18;;;1296:1;1280:18;;;;;;;;;1251:26;;1280:18;;;;;;;;;;;;;;;;;-1:-1:-1;;1331:16:132;;;1345:1;1331:16;;;;;;;;;1251:47;;-1:-1:-1;1308:20:132;;1331:16;;;;;;;;;;;-1:-1:-1;;1455:49:132;;-1:-1:-1;;;1455:49:132;;1498:4;1455:49;;;3020:74:141;1308:39:132;;-1:-1:-1;1432:20:132;;-1:-1:-1;;;;;1455:34:132;;;;;2993:18:141;;1455:49:132;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1432:72;-1:-1:-1;1522:16:132;;1518:118;;1558:63;-1:-1:-1;;;;;1558:37:132;;1596:10;1608:12;1558:37;:63::i;:::-;1650:11;1663:13;1680:72;1724:12;1738:13;1680:43;:72::i;:::-;1649:103;;;;1812:5;1790:3;1794:1;1790:6;;;;;;;;:::i;:::-;;;;;;;;;;:28;-1:-1:-1;;1938:50:132;;-1:-1:-1;;;1938:50:132;;1982:4;1938:50;;;3020:74:141;1914:21:132;;-1:-1:-1;;;;;;1938:35:132;;;;;2993:18:141;;1938:50:132;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1914:74;-1:-1:-1;2006:17:132;;2002:121;;2043:65;-1:-1:-1;;;;;2043:38:132;;2082:10;2094:13;2043:38;:65::i;:::-;2138:12;2152:13;2169:74;2213:13;2228:14;2169:43;:74::i;:::-;2137:106;;;;2303:6;2281:3;2285:1;2281:6;;;;;;;;:::i;:::-;;;;;;;;;;:29;-1:-1:-1;2795:21:132;;-1:-1:-1;2830:50:132;;-1:-1:-1;2856:10:132;2795:21;2830:17;:50::i;:::-;2916:53;2952:10;-1:-1:-1;;2916:28:132;:53::i;:::-;2894:3;2898:1;2894:6;;;;;;;;:::i;:::-;;;;;;:76;;;;;2331:650;3004:3;2991:7;2999:1;2991:10;;;;;;;;:::i;:::-;;;;;;;;;;:16;3041:15;;;3054:1;3041:15;;;;;;;;;3018:20;;3041:15;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3041:15:132;;;;;;;;;;;;;;;3018:38;;3076:4;3066;3071:1;3066:7;;;;;;;;:::i;:::-;;;;;;:14;;;;3090:34;3110:7;3119:4;3090:19;:34::i;:::-;1241:1890;;;1049:2082;;;;;:::o;12173:248:68:-;12254:7;;-1:-1:-1;;;;;17672:16:68;;17668:2;17657:32;17718:4;17714:16;;;12356:58;17657:32;17714:16;12405:8;12356:19;:58::i;:::-;12349:65;;;;;;12173:248;;;;;;:::o;5196:642:56:-;5615:23;5641:69;5669:4;5641:69;;;;;;;;;;;;;;;;;5649:5;-1:-1:-1;;;;;5641:27:56;;;:69;;;;;:::i;:::-;5615:95;;5728:10;:17;5749:1;5728:22;:56;;;;5765:10;5754:30;;;;;;;;;;;;:::i;:::-;5720:111;;;;-1:-1:-1;;;5720:111:56;;26328:2:141;5720:111:56;;;26310:21:141;26367:2;26347:18;;;26340:30;26406:34;26386:18;;;26379:62;26477:12;26457:18;;;26450:40;26507:19;;5720:111:56;26126:406:141;941:175:56;1050:58;;-1:-1:-1;;;;;25503:55:141;;1050:58:56;;;25485:74:141;25575:18;;;25568:34;;;1023:86:56;;1043:5;;1073:23;;25458:18:141;;1050:58:56;25311:297:141;6058:353:68;6149:5;6156:4;6173:24;6199:15;6216:13;6233:38;6255:5;6262:8;6233:21;:38::i;:::-;6172:99;;;;;;6282:11;6295:17;6316:38;6326:17;6345:8;6316:9;:38::i;:::-;6281:73;;;;6372:5;6379:8;:24;;;;;6391:12;6379:24;6364:40;;;;;;;;;6058:353;;;;;:::o;2647:312:57:-;2761:6;2736:21;:31;;2728:73;;;;-1:-1:-1;;;2728:73:57;;26739:2:141;2728:73:57;;;26721:21:141;26778:2;26758:18;;;26751:30;26817:31;26797:18;;;26790:59;26866:18;;2728:73:57;26537:353:141;2728:73:57;2813:12;2831:9;-1:-1:-1;;;;;2831:14:57;2853:6;2831:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2812:52;;;2882:7;2874:78;;;;-1:-1:-1;;;2874:78:57;;27307:2:141;2874:78:57;;;27289:21:141;27346:2;27326:18;;;27319:30;27385:34;27365:18;;;27358:62;27456:28;27436:18;;;27429:56;27502:19;;2874:78:57;27105:422:141;16760:299:68;16848:5;16866:7;16875:13;16892:38;16902:17;16921:8;16892:9;:38::i;:::-;16865:65;;;;16945:8;16940:95;;16976:48;;;;;;;;27702:25:141;;;27743:18;;;27736:34;;;27675:18;;16976:48:68;27532:244:141;16940:95:68;-1:-1:-1;17051:1:68;16760:299;-1:-1:-1;;;16760:299:68:o;4763:1318:131:-;4911:10;4848:24;1232:25:105;;;5028:4:131;1277::105;1270:20;;;1338:4;1325:18;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5104:18:131;;;;;;;;5169:16;;;;;;;;;1325:18:105;;-1:-1:-1;;5104:18:131;;5195:880;5219:4;:11;5215:1;:15;5195:880;;;5258:4;5263:1;5258:7;;;;;;;;:::i;:::-;;;;;;;5251:14;;5316:1;5283:4;:14;;;:23;;;:30;:34;5279:786;;;5338:24;5364:23;5391:4;:14;;;:26;;;-1:-1:-1;;;;;5391:32:131;;5445:438;;;;;;;;5485:4;:14;;;:20;;;-1:-1:-1;;;;;5445:438:131;;;;;5542:18;5445:438;;;;5596:4;:14;;;:23;;;5445:438;;;;5677:1;5445:438;;;;5714:45;5731:7;5740:4;:18;;;5714:16;:45::i;:::-;5445:438;;;;5793:10;5445:438;;;;5843:17;5445:438;;;5391:510;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5391:510:131;;;;;;;;;;;;:::i;:::-;5948:13;;5337:564;;-1:-1:-1;5337:564:131;-1:-1:-1;5948:17:131;5944:107;;5989:14;;:20;;;:43;;;;;-1:-1:-1;;;;;5989:24:131;;;;;;:43;;6014:9;;6025:6;;5989:43;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5944:107;5319:746;;5279:786;5232:3;;5195:880;;8561:3045:68;8696:7;8705:4;8828:1;8808:17;:21;8804:2796;;;8852:59;;;;;;;;27702:25:141;;;27743:18;;;27736:34;;;27675:18;;8852:59:68;27532:244:141;8804:2796:68;9010:17;9031:1;9010:22;9006:2594;;-1:-1:-1;9056:1:68;;-1:-1:-1;9059:4:68;9048:16;;9006:2594;9274:17;9555;;;9537:36;;9595:24;;;9591:123;;;9650:45;;-1:-1:-1;;;9650:45:68;;;;;27702:25:141;;;27743:18;;;27736:34;;;27675:18;;9650:45:68;27532:244:141;9591:123:68;9742:13;9769:20;9823:1;9807:13;:17;9803:1787;;;-1:-1:-1;;10085:13:68;:19;10081:91;;;10140:1;10143:5;10132:17;;;;;;;;;;10081:91;10532:13;10531:14;;10517:2;:29;10509:37;;10605:5;10583:19;:27;;;;;:::i;:::-;;;-1:-1:-1;;10868:20:68;;:43;;;;-1:-1:-1;10846:66:68;;-1:-1:-1;10846:66:68;9803:1787;10971:1;10955:13;:17;10951:639;;;11117:28;11131:13;11117:2;:28;:::i;:::-;11109:36;-1:-1:-1;11178:27:68;11109:36;11178:19;:27;:::i;:::-;11163:42;-1:-1:-1;11479:4:68;;-1:-1:-1;11457:27:68;;-1:-1:-1;;;;11457:27:68;10951:639;-1:-1:-1;11549:19:68;;-1:-1:-1;11570:4:68;;-1:-1:-1;;;9006:2594:68;8561:3045;;;;;;:::o;4108:223:57:-;4241:12;4272:52;4294:6;4302:4;4308:1;4311:12;4272:21;:52::i;:::-;4265:59;4108:223;-1:-1:-1;;;;4108:223:57:o;4678:800:68:-;4763:6;;;4845:17;;;4837:26;;5010:16;4994:33;;4990:472;;;5207:2;5199:5;:10;5223:1;5212:12;;5234:2;5226:5;:10;5240:1;5226:15;5184:58;;;;;;;;;4990:472;5424:5;;-1:-1:-1;5432:8:68;-1:-1:-1;5442:4:68;;-1:-1:-1;4678:800:68;;;;;;:::o;14352:2402::-;14437:11;14869:46;;;;;;14533:17;14589:8;14869:46;15193:668;;15250:4;15230:17;:24;:29;15226:135;;15304:3;15283:24;;;;15341:1;15329:13;;;;15226:135;15600:17;15578;15571:46;;;15564:151;;15662:2;15641:23;;;;15686:10;;;;;15564:151;;;15193:668;;;15757:17;15778:1;15757:22;15753:94;;-1:-1:-1;2277:1:68;;-1:-1:-1;15823:4:68;;-1:-1:-1;15803:25:68;;-1:-1:-1;15803:25:68;15753:94;16071:8;16058;16052:27;;;16048:393;;16273:1;16262:8;:12;16258:85;;;-1:-1:-1;2277:1:68;;-1:-1:-1;2277:1:68;;-1:-1:-1;16298:26:68;;-1:-1:-1;16298:26:68;16258:85;16367:59;;-1:-1:-1;;;16367:59:68;;;;;27702:25:141;;;27743:18;;;27736:34;;;27675:18;;16367:59:68;27532:244:141;16048:393:68;-1:-1:-1;;;;;;;16674:28:68;;16708:4;16704:19;;;16671:53;;-1:-1:-1;14352:2402:68;;;;;:::o;7813:2299:102:-;7948:18;8006:24;8047:14;:21;8033:36;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;8033:36:102;;8006:63;;8218:21;8292:1;8268:14;:21;:25;:57;;8324:1;8268:57;;;8296:14;:21;8320:1;8296:25;8268:57;8246:11;:18;8242:1;:22;:84;8218:108;;8341:26;8386:13;8370:30;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8341:59;;8414:14;8464:17;2784:4;2778:11;;2820:1;2802:20;;2864:8;2857:4;2842:20;;2835:38;2915:9;2893:20;;;2886:39;2688:26;2951:20;;2938:34;;;2778:11;2649:339;8464:17;8446:7;8454:6;8446:15;;;;;;;;:::i;:::-;;;;;;:35;;;;8501:9;8496:140;8520:11;:18;8516:1;:22;8496:140;;;8563:8;;;;;;;8607:11;8619:1;8607:14;;;;;;;;:::i;:::-;;;;;;;8589:7;8597:6;8589:15;;;;;;;;:::i;:::-;;;;;;;;;;:32;8540:3;;8496:140;;;-1:-1:-1;8654:21:102;;:25;8650:1417;;8699:8;;;;;;;8743:7;8725;8733:6;8725:15;;;;;;;;:::i;:::-;;;;;;:25;;;;8774:9;8769:1284;8793:14;:21;8789:1;:25;8769:1284;;;9471:284;9537:14;9552:1;9537:17;;;;;;;;:::i;:::-;;;;;;;:24;;;9591:81;9620:51;9645:14;9660:1;9645:17;;;;;;;;:::i;:::-;;;;;;;:25;;;3956:13:20;;3971:4;3952:24;;;3933:17;;3923:54;;3783:210;9620:51:102;7389:34:61;7189:15;7376:48;;;7444:4;7437:18;;;;7495:4;7479:21;;;7120:396;9591:81:102;9702:14;9717:1;9702:17;;;;;;;;:::i;:::-;;;;;;;:27;;;9471:36;:284::i;:::-;8843:1010;;9811:19;;;;;;;;2814:25:141;;;2787:18;;9811:19:102;2668:177:141;8843:1010:102;9912:14;9927:1;9912:17;;;;;;;;:::i;:::-;;;;;;;:24;;;-1:-1:-1;;;;;9896:42:102;9888:51;;9875:7;9883:1;9875:10;;;;;;;;:::i;:::-;;;;;;:64;;;;;9961:8;;;;;;;10009:14;10024:1;10009:17;;;;;;;;:::i;:::-;;;;;;;:25;;;9991:7;9999:6;9991:15;;;;;;;;:::i;:::-;;;;;;;;;;:43;8816:3;;8769:1284;;;;8650:1417;-1:-1:-1;10088:7:102;7813:2299;-1:-1:-1;;;;;7813:2299:102:o;5165:446:57:-;5330:12;5387:5;5362:21;:30;;5354:81;;;;-1:-1:-1;;;5354:81:57;;33965:2:141;5354:81:57;;;33947:21:141;34004:2;33984:18;;;33977:30;34043:34;34023:18;;;34016:62;34114:8;34094:18;;;34087:36;34140:19;;5354:81:57;33763:402:141;5354:81:57;5446:12;5460:23;5487:6;-1:-1:-1;;;;;5487:11:57;5506:5;5513:4;5487:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5445:73;;;;5535:69;5562:6;5570:7;5579:10;5591:12;5535:26;:69::i;:::-;5528:76;5165:446;-1:-1:-1;;;;;;;5165:446:57:o;1014:366:62:-;1120:4;1137:17;1156:24;1184:33;1201:4;1207:9;1184:16;:33::i;:::-;1136:81;;-1:-1:-1;1136:81:62;-1:-1:-1;1256:26:62;1247:5;:35;;;;;;;;:::i;:::-;;:58;;;;;1299:6;-1:-1:-1;;;;;1286:19:62;:9;-1:-1:-1;;;;;1286:19:62;;1247:58;1246:127;;;;1322:51;1349:6;1357:4;1363:9;1322:26;:51::i;:::-;1227:146;1014:366;-1:-1:-1;;;;;;1014:366:62:o;7671:628:57:-;7851:12;7879:7;7875:418;;;7906:10;:17;7927:1;7906:22;7902:286;;-1:-1:-1;;;;;1702:19:57;;;8113:60;;;;-1:-1:-1;;;8113:60:57;;34853:2:141;8113:60:57;;;34835:21:141;34892:2;34872:18;;;34865:30;34931:31;34911:18;;;34904:59;34980:18;;8113:60:57;34651:353:141;8113:60:57;-1:-1:-1;8208:10:57;8201:17;;7875:418;8249:33;8257:10;8269:12;8249:7;:33::i;2145:730:61:-;2226:7;2235:12;2263:9;:16;2283:2;2263:22;2259:610;;2599:4;2584:20;;2578:27;2648:4;2633:20;;2627:27;2705:4;2690:20;;2684:27;2301:9;2676:36;2746:25;2757:4;2676:36;2578:27;2627;2746:10;:25::i;:::-;2739:32;;;;;;;;;2259:610;-1:-1:-1;2818:1:61;;-1:-1:-1;2822:35:61;2802:56;;1786:473:62;1929:4;1946:12;1960:19;1983:6;-1:-1:-1;;;;;1983:17:62;2037:34;;;2073:4;2079:9;2014:75;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;2014:75:62;;;;;;;;;;;;;;-1:-1:-1;;;;;2014:75:62;-1:-1:-1;;;;;;2014:75:62;;;;;;;;;;1983:116;;;;2014:75;1983:116;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1945:154;;;;2117:7;:42;;;;;2157:2;2140:6;:13;:19;;2117:42;:134;;;;-1:-1:-1;2175:29:62;;2216:34;;2175:29;;;;;;;;;;;;:::i;:::-;:76;;1786:473;-1:-1:-1;;;;;;1786:473:62:o;8821:540:57:-;8980:17;;:21;8976:379;;9208:10;9202:17;9264:15;9251:10;9247:2;9243:19;9236:44;8976:379;9331:12;9324:20;;-1:-1:-1;;;9324:20:57;;;;;;;;:::i;5009:1456:61:-;5097:7;;6021:66;6008:79;;6004:161;;;-1:-1:-1;6119:1:61;;-1:-1:-1;6123:30:61;6103:51;;6004:161;6276:24;;;6259:14;6276:24;;;;;;;;;35942:25:141;;;36015:4;36003:17;;35983:18;;;35976:45;;;;36037:18;;;36030:34;;;36080:18;;;36073:34;;;6276:24:61;;35914:19:141;;6276:24:61;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6276:24:61;;-1:-1:-1;;6276:24:61;;;-1:-1:-1;;;;;;;6314:20:61;;6310:101;;6366:1;6370:29;6350:50;;;;;;;6310:101;6429:6;-1:-1:-1;6437:20:61;;-1:-1:-1;5009:1456:61;;;;;;;;:::o;14:332:141:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;-1:-1:-1;;;;;;223:5:141;219:78;212:5;209:89;199:117;;312:1;309;302:12;199:117;335:5;14:332;-1:-1:-1;;;14:332:141:o;543:168::-;-1:-1:-1;;;;;636:5:141;632:54;625:5;622:65;612:93;;701:1;698;691:12;612:93;543:168;:::o;716:855::-;881:6;889;897;950:2;938:9;929:7;925:23;921:32;918:52;;;966:1;963;956:12;918:52;1005:9;992:23;1024:45;1063:5;1024:45;:::i;:::-;1088:5;-1:-1:-1;1144:2:141;1129:18;;1116:32;1167:18;1197:14;;;1194:34;;;1224:1;1221;1214:12;1194:34;1247:22;;;;1303:3;1285:16;;;1281:26;1278:46;;;1320:1;1317;1310:12;1278:46;1343:2;;-1:-1:-1;1398:2:141;1383:18;;1370:32;;1414:16;;;1411:36;;;1443:1;1440;1433:12;1411:36;-1:-1:-1;1466:24:141;;1524:2;1506:16;;;1502:25;1499:45;;;1540:1;1537;1530:12;1499:45;1563:2;1553:12;;;716:855;;;;;:::o;1576:1087::-;1736:6;1744;1752;1760;1768;1776;1829:3;1817:9;1808:7;1804:23;1800:33;1797:53;;;1846:1;1843;1836:12;1797:53;1885:9;1872:23;1904:45;1943:5;1904:45;:::i;:::-;1968:5;-1:-1:-1;2025:2:141;2010:18;;1997:32;2038:47;1997:32;2038:47;:::i;:::-;2104:7;-1:-1:-1;2158:2:141;2143:18;;2130:32;;-1:-1:-1;2209:2:141;2194:18;;2181:32;;-1:-1:-1;2264:3:141;2249:19;;2236:33;2288:18;2318:14;;;2315:34;;;2345:1;2342;2335:12;2315:34;2383:6;2372:9;2368:22;2358:32;;2428:7;2421:4;2417:2;2413:13;2409:27;2399:55;;2450:1;2447;2440:12;2399:55;2490:2;2477:16;2516:2;2508:6;2505:14;2502:34;;;2532:1;2529;2522:12;2502:34;2577:7;2572:2;2563:6;2559:2;2555:15;2551:24;2548:37;2545:57;;;2598:1;2595;2588:12;2545:57;2629:2;2625;2621:11;2611:21;;2651:6;2641:16;;;;;1576:1087;;;;;;;;:::o;3105:184::-;-1:-1:-1;;;3154:1:141;3147:88;3254:4;3251:1;3244:15;3278:4;3275:1;3268:15;3294:253;3366:2;3360:9;3408:4;3396:17;;3443:18;3428:34;;3464:22;;;3425:62;3422:88;;;3490:18;;:::i;:::-;3526:2;3519:22;3294:253;:::o;3552:257::-;3624:4;3618:11;;;3656:17;;3703:18;3688:34;;3724:22;;;3685:62;3682:88;;;3750:18;;:::i;3814:275::-;3885:2;3879:9;3950:2;3931:13;;-1:-1:-1;;3927:27:141;3915:40;;3985:18;3970:34;;4006:22;;;3967:62;3964:88;;;4032:18;;:::i;:::-;4068:2;4061:22;3814:275;;-1:-1:-1;3814:275:141:o;4094:530::-;4136:5;4189:3;4182:4;4174:6;4170:17;4166:27;4156:55;;4207:1;4204;4197:12;4156:55;4243:6;4230:20;4269:18;4265:2;4262:26;4259:52;;;4291:18;;:::i;:::-;4335:55;4378:2;4359:13;;-1:-1:-1;;4355:27:141;4384:4;4351:38;4335:55;:::i;:::-;4415:2;4406:7;4399:19;4461:3;4454:4;4449:2;4441:6;4437:15;4433:26;4430:35;4427:55;;;4478:1;4475;4468:12;4427:55;4543:2;4536:4;4528:6;4524:17;4517:4;4508:7;4504:18;4491:55;4591:1;4566:16;;;4584:4;4562:27;4555:38;;;;4570:7;4094:530;-1:-1:-1;;;4094:530:141:o;4629:198::-;4704:4;4737:18;4729:6;4726:30;4723:56;;;4759:18;;:::i;:::-;-1:-1:-1;4804:1:141;4800:14;4816:4;4796:25;;4629:198::o;4832:2535::-;4901:5;4954:3;4947:4;4939:6;4935:17;4931:27;4921:55;;4972:1;4969;4962:12;4921:55;5008:6;4995:20;5034:4;5058:75;5074:58;5129:2;5074:58;:::i;:::-;5058:75;:::i;:::-;5167:15;;;5253:1;5249:10;;;;5237:23;;5233:32;;;5198:12;;;;5277:15;;;5274:35;;;5305:1;5302;5295:12;5274:35;5341:2;5333:6;5329:15;5353:1985;5369:6;5364:3;5361:15;5353:1985;;;5455:3;5442:17;5482:18;5532:2;5519:11;5516:19;5513:39;;;5548:1;5545;5538:12;5513:39;5575:24;;;;5647:4;5623:12;;;-1:-1:-1;;5619:26:141;5615:37;5612:127;;;5693:1;5722:2;5718;5711:14;5612:127;5765:22;;:::i;:::-;5836:2;5832;5828:11;5815:25;5853:47;5892:7;5853:47;:::i;:::-;5913:22;;5958:2;6002:11;;;5989:25;6030:16;;;6027:106;;;6087:1;6116:2;6112;6105:14;6027:106;6156:17;;6208:2;6200:11;;6196:21;-1:-1:-1;6186:119:141;;6259:1;6288:2;6284;6277:14;6186:119;6350:2;6346;6342:11;6329:25;6380:76;6396:59;6451:3;6396:59;:::i;6380:76::-;6500:18;;;6599:1;6595:11;;;;6587:20;;6583:29;;;6540:14;;;;6628:17;;;6625:110;;;6687:1;6717:3;6712;6705:16;6625:110;6761:11;;;;6785:174;6803:8;6796:5;6793:19;6785:174;;;6885:19;;6871:34;;6824:14;;;;6931;;;;6785:174;;;6979:14;;;6972:29;-1:-1:-1;;;7051:4:141;7043:13;;7030:27;7073:16;;;7070:109;;;7131:1;7161:3;7156;7149:16;7070:109;7215:49;7260:3;7255:2;7244:8;7240:2;7236:17;7232:26;7215:49;:::i;:::-;7199:14;;;7192:73;;;;-1:-1:-1;7278:18:141;;-1:-1:-1;;7316:12:141;;;;5386;;5353:1985;;;-1:-1:-1;7356:5:141;4832:2535;-1:-1:-1;;;;;;4832:2535:141:o;7372:1240::-;7474:9;7533:4;7525:5;7509:14;7505:26;7501:37;7498:57;;;7551:1;7548;7541:12;7498:57;7579:22;;:::i;:::-;7637:5;7624:19;7662:18;7703:2;7695:6;7692:14;7689:34;;;7719:1;7716;7709:12;7689:34;7753:6;7746:5;7742:18;7732:28;;7801:4;7796:2;7780:14;7776:23;7772:34;7769:54;;;7819:1;7816;7809:12;7769:54;7847:22;;:::i;:::-;7906:2;7893:16;7918:47;7957:7;7918:47;:::i;:::-;7974:24;;8043:2;8035:11;;8022:25;8056:47;8022:25;8056:47;:::i;:::-;8132:2;8119:16;;8112:33;8191:4;8183:13;;8170:27;8209:16;;;8206:36;;;8238:1;8235;8228:12;8206:36;8278:51;8314:14;8303:8;8299:2;8295:17;8278:51;:::i;:::-;8271:4;8258:18;;8251:79;-1:-1:-1;8339:24:141;;8412:2;8401:14;;8388:28;;-1:-1:-1;8428:16:141;;;8425:36;;;8457:1;8454;8447:12;8425:36;;8495:81;8561:14;8550:8;8543:5;8539:20;8495:81;:::i;:::-;8490:2;8477:16;;8470:107;-1:-1:-1;8481:7:141;7372:1240;-1:-1:-1;;7372:1240:141:o;8617:250::-;8702:1;8712:113;8726:6;8723:1;8720:13;8712:113;;;8802:11;;;8796:18;8783:11;;;8776:39;8748:2;8741:10;8712:113;;;-1:-1:-1;;8859:1:141;8841:16;;8834:27;8617:250::o;8872:270::-;8913:3;8951:5;8945:12;8978:6;8973:3;8966:19;8994:76;9063:6;9056:4;9051:3;9047:14;9040:4;9033:5;9029:16;8994:76;:::i;:::-;9124:2;9103:15;-1:-1:-1;;9099:29:141;9090:39;;;;9131:4;9086:50;;8872:270;-1:-1:-1;;8872:270:141:o;9147:439::-;9200:3;9238:5;9232:12;9265:6;9260:3;9253:19;9291:4;9320;9315:3;9311:14;9304:21;;9359:4;9352:5;9348:16;9382:1;9392:169;9406:6;9403:1;9400:13;9392:169;;;9467:13;;9455:26;;9501:12;;;;9536:15;;;;9428:1;9421:9;9392:169;;;-1:-1:-1;9577:3:141;;9147:439;-1:-1:-1;;;;;9147:439:141:o;9591:1751::-;9733:4;9762:2;9791;9780:9;9773:21;9813:2;9850:6;9844:13;9876:4;9916;9911:2;9900:9;9896:18;9889:32;-1:-1:-1;;;;;10043:2:141;10028:12;10022:19;10018:28;10013:2;10002:9;9998:18;9991:56;10118:2;10112;10098:12;10094:21;10088:28;10084:37;10078:3;10067:9;10063:19;10056:66;10177:4;10163:12;10159:23;10153:30;10131:52;;10220:2;10214:3;10203:9;10199:19;10192:31;10243:53;10291:3;10280:9;10276:19;10260:14;10243:53;:::i;:::-;10333:15;;;10327:22;-1:-1:-1;;10417:19:141;;;10413:28;;10406:4;10391:20;;10384:58;10488:21;;10518:19;;;10417;;-1:-1:-1;10644:23:141;;;;10553:12;;;;10605:1;10601:14;;;10592:24;;10588:33;;10685:1;10695:618;10709:6;10706:1;10703:13;10695:618;;;10792:2;10786:3;10778:6;10774:16;10770:25;10765:3;10758:38;10825:6;10819:13;10875:2;10870;10864:9;10860:18;10852:6;10845:34;10928:2;10924;10920:11;10914:18;10969:2;10964;10956:6;10952:15;10945:27;10999:61;11056:2;11048:6;11044:15;11028:14;10999:61;:::i;:::-;11101:11;;;11095:18;11150:19;;;11133:15;;;11126:44;11095:18;10985:75;-1:-1:-1;11193:40:141;10985:75;11095:18;11193:40;:::i;:::-;11256:15;;;;11291:12;;;;11183:50;-1:-1:-1;;;10731:1:141;10724:9;10695:618;;;-1:-1:-1;11330:6:141;9591:1751;-1:-1:-1;;;;;;;;;;;;9591:1751:141:o;11347:583::-;11478:4;11484:6;11544:11;11531:25;11638:2;11634:7;11623:8;11607:14;11603:29;11599:43;11579:18;11575:68;11565:96;;11657:1;11654;11647:12;11565:96;11684:33;;11736:20;;;-1:-1:-1;11779:18:141;11768:30;;11765:50;;;11811:1;11808;11801:12;11765:50;11844:4;11832:17;;-1:-1:-1;11895:1:141;11891:14;;;11875;11871:35;11861:46;;11858:66;;;11920:1;11917;11910:12;11935:184;-1:-1:-1;;;11984:1:141;11977:88;12084:4;12081:1;12074:15;12108:4;12105:1;12098:15;12124:336;12228:4;12286:11;12273:25;12380:3;12376:8;12365;12349:14;12345:29;12341:44;12321:18;12317:69;12307:97;;12400:1;12397;12390:12;12307:97;12421:33;;;;;12124:336;-1:-1:-1;;12124:336:141:o;12465:326::-;12559:4;12617:11;12604:25;12711:3;12707:8;12696;12680:14;12676:29;12672:44;12652:18;12648:69;12638:97;;12731:1;12728;12721:12;12796:570;12914:4;12920:6;12980:11;12967:25;13074:2;13070:7;13059:8;13043:14;13039:29;13035:43;13015:18;13011:68;13001:96;;13093:1;13090;13083:12;13001:96;13120:33;;13172:20;;;-1:-1:-1;13215:18:141;13204:30;;13201:50;;;13247:1;13244;13237:12;13201:50;13280:4;13268:17;;-1:-1:-1;13331:1:141;13327:14;;;13311;13307:35;13297:46;;13294:66;;;13356:1;13353;13346:12;13371:261;13430:6;13483:2;13471:9;13462:7;13458:23;13454:32;13451:52;;;13499:1;13496;13489:12;13451:52;13538:9;13525:23;13557:45;13596:5;13557:45;:::i;13637:546::-;13733:5;13740:6;13800:3;13787:17;13886:2;13882:7;13871:8;13855:14;13851:29;13847:43;13827:18;13823:68;13813:96;;13905:1;13902;13895:12;13813:96;13933:33;;14037:4;14024:18;;;-1:-1:-1;13985:21:141;;-1:-1:-1;14065:18:141;14054:30;;14051:50;;;14097:1;14094;14087:12;14051:50;14151:6;14148:1;14144:14;14128;14124:35;14117:5;14113:47;14110:67;;;14173:1;14170;14163:12;14188:296;14259:5;14318:3;14305:17;14404:2;14400:7;14389:8;14373:14;14369:29;14365:43;14345:18;14341:68;14331:96;;14423:1;14420;14413:12;14331:96;14445:33;;;;14188:296;-1:-1:-1;;14188:296:141:o;14489:500::-;14547:5;14554:6;14614:3;14601:17;14700:2;14696:7;14685:8;14669:14;14665:29;14661:43;14641:18;14637:68;14627:96;;14719:1;14716;14709:12;14627:96;14747:33;;14851:4;14838:18;;;-1:-1:-1;14799:21:141;;-1:-1:-1;14879:18:141;14868:30;;14865:50;;;14911:1;14908;14901:12;14865:50;14958:6;14942:14;14938:27;14931:5;14927:39;14924:59;;;14979:1;14976;14969:12;14994:266;15082:6;15077:3;15070:19;15134:6;15127:5;15120:4;15115:3;15111:14;15098:43;-1:-1:-1;15186:1:141;15161:16;;;15179:4;15157:27;;;15150:38;;;;15242:2;15221:15;;;-1:-1:-1;;15217:29:141;15208:39;;;15204:50;;14994:266::o;15265:533::-;15348:5;15355:6;15415:3;15402:17;15501:2;15497:7;15486:8;15470:14;15466:29;15462:43;15442:18;15438:68;15428:96;;15520:1;15517;15510:12;15428:96;15548:33;;15652:4;15639:18;;;-1:-1:-1;15600:21:141;;-1:-1:-1;15680:18:141;15669:30;;15666:50;;;15712:1;15709;15702:12;15666:50;15766:6;15763:1;15759:14;15743;15739:35;15732:5;15728:47;15725:67;;;15788:1;15785;15778:12;15803:665;15916:6;15911:3;15904:19;15886:3;15942:4;15971;15966:3;15962:14;15955:21;;15999:5;16022:1;16032:411;16046:6;16043:1;16040:13;16032:411;;;16123:6;16110:20;16143:47;16182:7;16143:47;:::i;:::-;-1:-1:-1;;;;;16215:56:141;16203:69;;16319:15;;;16306:29;16292:12;;;16285:51;16359:4;16383:12;;;;16418:15;;;;16068:1;16061:9;16032:411;;16473:1664;16610:19;;;16648:4;16668:12;;;;16567:3;;16699:1;16736:14;;;16725:26;;16721:35;;16779:5;16567:3;;16833:1278;16849:6;16844:3;16841:15;16833:1278;;;16918:16;;;-1:-1:-1;;16914:30:141;16902:43;;16968:58;17019:6;17012:5;16968:58;:::i;:::-;17049:4;17094:2;17081:16;17110:47;17149:7;17110:47;:::i;:::-;-1:-1:-1;;;;;17183:56:141;17170:70;;17287:85;17360:11;;;17364:2;17287:85;:::i;:::-;17407:2;17402;17396:4;17392:13;17385:25;17445:12;17440:2;17434:4;17430:13;17423:35;17481:3;17471:13;;17517:66;17503:12;17500:84;17497:104;;;17597:1;17594;17587:12;17497:104;17630:21;;;17692:12;17677:13;;;17664:51;17738:19;;;-1:-1:-1;17780:4:141;17835:47;17870:11;;;17874:2;17835:47;:::i;:::-;17797:85;;17936:2;17929:4;17925:2;17921:13;17917:22;17912:2;17906:4;17902:13;17895:45;17961:70;18027:2;18023;18019:11;18003:14;17987;17961:70;:::i;:::-;18089:12;;;;17953:78;-1:-1:-1;;;18054:15:141;;;;-1:-1:-1;;;16875:1:141;16866:11;16833:1278;;;-1:-1:-1;18127:4:141;;16473:1664;-1:-1:-1;;;;;;;;;16473:1664:141:o;18142:4047::-;18310:4;18339:2;18368;18357:9;18350:21;18409:3;18398:9;18394:19;18462:6;18449:20;18444:2;18433:9;18429:18;18422:48;18489:2;18552;18544:6;18540:15;18527:29;18522:2;18511:9;18507:18;18500:57;18576:2;18639;18631:6;18627:15;18614:29;18609:2;18598:9;18594:18;18587:57;18687:93;18776:2;18768:6;18764:15;18756:6;18687:93;:::i;:::-;18817:4;18811:3;18800:9;18796:19;18789:33;18842:6;18872:12;18864:6;18857:28;18916:3;18905:9;18901:19;18894:26;;18985:3;18969:12;18966:1;18962:20;18951:9;18947:36;18943:46;18929:60;;19012:12;19042:1;19052:2871;19066:12;19063:1;19060:19;19052:2871;;;19137:22;;;-1:-1:-1;;19133:37:141;19121:50;;19210:20;;19285:14;19281:33;;;-1:-1:-1;;19277:48:141;19253:73;;19243:101;;19340:1;19337;19330:12;19243:101;19370:37;;19448:19;;19524:14;19520:26;;;-1:-1:-1;;19516:41:141;19490:68;;19480:96;;19572:1;19569;19562:12;19480:96;19664:3;19649:19;;19604:32;;19696:21;;19730:47;19696:21;19730:47;:::i;:::-;-1:-1:-1;;;;;19893:2:141;19884:7;19880:16;19874:3;19866:6;19862:16;19855:42;19932:70;19998:2;19989:7;19985:16;19976:7;19932:70;:::i;:::-;19910:92;;20041:4;20034;20026:6;20022:17;20015:31;20087:14;20074:28;20115:47;20154:7;20115:47;:::i;:::-;20200:16;;20194:3;20182:16;;20175:42;20258:23;;;20245:37;20295:47;20245:37;20295:47;:::i;:::-;20380:16;20374:3;20362:16;;20355:42;20448:71;20495:23;;;20499:14;20448:71;:::i;:::-;20410:109;;20557:2;20551:3;20543:6;20539:16;20532:28;20584:75;20654:3;20646:6;20642:16;20626:14;20610;20584:75;:::i;:::-;20573:86;;;20710:82;20788:2;20779:7;20775:16;20766:7;20710:82;:::i;:::-;20819:3;20815:8;20883:2;20874:6;20869:3;20865:16;20861:25;20855:3;20847:6;20843:16;20836:51;20914:87;20997:3;20981:14;20965;20914:87;:::i;:::-;20900:101;;21052:82;21130:2;21121:7;21117:16;21108:7;21052:82;:::i;:::-;21014:120;;;;21197:2;21188:6;21180;21176:19;21172:28;21166:3;21158:6;21154:16;21147:54;;21228:90;21311:6;21295:14;21279;21228:90;:::i;:::-;21214:104;;;;21382:3;21373:7;21369:17;21356:31;21350:3;21342:6;21338:16;21331:57;21449:2;21442:5;21438:14;21425:28;21420:2;21412:6;21408:15;21401:53;21515:2;21508:5;21504:14;21491:28;21486:2;21478:6;21474:15;21467:53;21571:91;21658:2;21651:5;21647:14;21640:5;21571:91;:::i;:::-;21533:129;;;;21711:6;21703;21699:19;21694:2;21686:6;21682:15;21675:44;21742:101;21836:6;21820:14;21804;21742:101;:::i;:::-;21732:111;-1:-1:-1;;;21901:12:141;;;;-1:-1:-1;21866:15:141;;;;19094:1;19087:9;19052:2871;;;19056:3;;;;;;;21970:56;22021:3;22013:6;22009:16;22001:6;21970:56;:::i;:::-;22068:22;;;-1:-1:-1;;22064:36:141;22057:4;22042:20;;22035:66;21932:94;-1:-1:-1;22118:65:141;22072:6;21932:94;22144:14;22118:65;:::i;22194:299::-;22327:6;22335;22388:2;22376:9;22367:7;22363:23;22359:32;22356:52;;;22404:1;22401;22394:12;22356:52;-1:-1:-1;;22427:16:141;;22483:2;22468:18;;;22462:25;22427:16;;22462:25;;-1:-1:-1;22194:299:141:o;22772:273::-;22840:6;22893:2;22881:9;22872:7;22868:23;22864:32;22861:52;;;22909:1;22906;22899:12;22861:52;22941:9;22935:16;22991:4;22984:5;22980:16;22973:5;22970:27;22960:55;;23011:1;23008;23001:12;23050:184;-1:-1:-1;;;23099:1:141;23092:88;23199:4;23196:1;23189:15;23223:4;23220:1;23213:15;23239:135;23278:3;23299:17;;;23296:43;;23319:18;;:::i;:::-;-1:-1:-1;23366:1:141;23355:13;;23239:135::o;24007:184::-;24077:6;24130:2;24118:9;24109:7;24105:23;24101:32;24098:52;;;24146:1;24143;24136:12;24098:52;-1:-1:-1;24169:16:141;;24007:184;-1:-1:-1;24007:184:141:o;25844:277::-;25911:6;25964:2;25952:9;25943:7;25939:23;25935:32;25932:52;;;25980:1;25977;25970:12;25932:52;26012:9;26006:16;26065:5;26058:13;26051:21;26044:5;26041:32;26031:60;;26087:1;26084;26077:12;27781:620;27844:3;27875;27907:5;27901:12;27934:6;27929:3;27922:19;27960:4;27989;27984:3;27980:14;27973:21;;28047:4;28037:6;28034:1;28030:14;28023:5;28019:26;28015:37;28086:4;28079:5;28075:16;28109:1;28119:256;28133:6;28130:1;28127:13;28119:256;;;28220:2;28216:7;28208:5;28202:4;28198:16;28194:30;28189:3;28182:43;28246:49;28290:4;28281:6;28275:13;28246:49;:::i;:::-;28353:12;;;;28238:57;-1:-1:-1;28318:15:141;;;;28155:1;28148:9;28119:256;;;-1:-1:-1;28391:4:141;;27781:620;-1:-1:-1;;;;;;;27781:620:141:o;28406:1197::-;28585:2;28574:9;28567:21;-1:-1:-1;;;;;28634:6:141;28628:13;28624:62;28619:2;28608:9;28604:18;28597:90;28741:2;28733:6;28729:15;28723:22;28718:2;28707:9;28703:18;28696:50;28548:4;28793:2;28785:6;28781:15;28775:22;28833:4;28828:2;28817:9;28813:18;28806:32;28861:51;28907:3;28896:9;28892:19;28878:12;28861:51;:::i;:::-;28847:65;;28967:2;28959:6;28955:15;28949:22;28943:3;28932:9;28928:19;28921:51;29021:3;29013:6;29009:16;29003:23;29049:2;29045:7;29117:2;29105:9;29097:6;29093:22;29089:31;29083:3;29072:9;29068:19;29061:60;29144:62;29199:6;29183:14;29144:62;:::i;:::-;29130:76;;29255:3;29247:6;29243:16;29237:23;29215:45;;29325:2;29313:9;29305:6;29301:22;29297:31;29291:3;29280:9;29276:19;29269:60;29352:52;29397:6;29381:14;29352:52;:::i;:::-;29338:66;;29453:3;29445:6;29441:16;29435:23;29413:45;;29524:2;29512:9;29504:6;29500:22;29496:31;29489:4;29478:9;29474:20;29467:61;;29545:52;29590:6;29574:14;29545:52;:::i;:::-;29537:60;28406:1197;-1:-1:-1;;;;;28406:1197:141:o;29608:680::-;29673:5;29726:3;29719:4;29711:6;29707:17;29703:27;29693:55;;29744:1;29741;29734:12;29693:55;29773:6;29767:13;29799:4;29823:75;29839:58;29894:2;29839:58;:::i;29823:75::-;29920:3;29944:2;29939:3;29932:15;29972:4;29967:3;29963:14;29956:21;;30029:4;30023:2;30020:1;30016:10;30008:6;30004:23;30000:34;29986:48;;30057:3;30049:6;30046:15;30043:35;;;30074:1;30071;30064:12;30043:35;30110:4;30102:6;30098:17;30124:135;30140:6;30135:3;30132:15;30124:135;;;30206:10;;30194:23;;30237:12;;;;30157;;30124:135;;30293:1180;30453:6;30461;30514:2;30502:9;30493:7;30489:23;30485:32;30482:52;;;30530:1;30527;30520:12;30482:52;30563:9;30557:16;30592:18;30633:2;30625:6;30622:14;30619:34;;;30649:1;30646;30639:12;30619:34;30687:6;30676:9;30672:22;30662:32;;30732:7;30725:4;30721:2;30717:13;30713:27;30703:55;;30754:1;30751;30744:12;30703:55;30783:2;30777:9;30805:4;30829:75;30845:58;30900:2;30845:58;:::i;30829:75::-;30938:15;;;31020:1;31016:10;;;;31008:19;;31004:28;;;30969:12;;;;31044:19;;;31041:39;;;31076:1;31073;31066:12;31041:39;31100:11;;;;31120:135;31136:6;31131:3;31128:15;31120:135;;;31202:10;;31190:23;;31153:12;;;;31233;;;;31120:135;;;31310:18;;;31304:25;31274:5;;-1:-1:-1;31304:25:141;;-1:-1:-1;;;31341:16:141;;;31338:36;;;31370:1;31367;31360:12;31338:36;;31393:74;31459:7;31448:8;31437:9;31433:24;31393:74;:::i;:::-;31383:84;;;30293:1180;;;;;:::o;31478:368::-;31721:6;31710:9;31703:25;31764:2;31759;31748:9;31744:18;31737:30;31684:4;31784:56;31836:2;31825:9;31821:18;31813:6;31784:56;:::i;31851:184::-;-1:-1:-1;;;31900:1:141;31893:88;32000:4;31997:1;31990:15;32024:4;32021:1;32014:15;32040:416;32129:1;32166:5;32129:1;32180:270;32201:7;32191:8;32188:21;32180:270;;;32260:4;32256:1;32252:6;32248:17;32242:4;32239:27;32236:53;;;32269:18;;:::i;:::-;32319:7;32309:8;32305:22;32302:55;;;32339:16;;;;32302:55;32418:22;;;;32378:15;;;;32180:270;;;32184:3;32040:416;;;;;:::o;32461:806::-;32510:5;32540:8;32530:80;;-1:-1:-1;32581:1:141;32595:5;;32530:80;32629:4;32619:76;;-1:-1:-1;32666:1:141;32680:5;;32619:76;32711:4;32729:1;32724:59;;;;32797:1;32792:130;;;;32704:218;;32724:59;32754:1;32745:10;;32768:5;;;32792:130;32829:3;32819:8;32816:17;32813:43;;;32836:18;;:::i;:::-;-1:-1:-1;;32892:1:141;32878:16;;32907:5;;32704:218;;33006:2;32996:8;32993:16;32987:3;32981:4;32978:13;32974:36;32968:2;32958:8;32955:16;32950:2;32944:4;32941:12;32937:35;32934:77;32931:159;;;-1:-1:-1;33043:19:141;;;33075:5;;32931:159;33122:34;33147:8;33141:4;33122:34;:::i;:::-;33192:6;33188:1;33184:6;33180:19;33171:7;33168:32;33165:58;;;33203:18;;:::i;:::-;33241:20;;32461:806;-1:-1:-1;;;32461:806:141:o;33272:131::-;33332:5;33361:36;33388:8;33382:4;33361:36;:::i;33408:168::-;33481:9;;;33512;;33529:15;;;33523:22;;33509:37;33499:71;;33550:18;;:::i;34170:287::-;34299:3;34337:6;34331:13;34353:66;34412:6;34407:3;34400:4;34392:6;34388:17;34353:66;:::i;34462:184::-;-1:-1:-1;;;34511:1:141;34504:88;34611:4;34608:1;34601:15;34635:4;34632:1;34625:15;35009:288;35184:6;35173:9;35166:25;35227:2;35222;35211:9;35207:18;35200:30;35147:4;35247:44;35287:2;35276:9;35272:18;35264:6;35247:44;:::i;35491:219::-;35640:2;35629:9;35622:21;35603:4;35660:44;35700:2;35689:9;35685:18;35677:6;35660:44;:::i","linkReferences":{},"immutableReferences":{"66496":[{"start":226,"length":32},{"start":526,"length":32},{"start":607,"length":32}],"67464":[{"start":292,"length":32},{"start":1352,"length":32},{"start":1405,"length":32},{"start":1763,"length":32},{"start":1891,"length":32}]}},"methodIdentifiers":{"arb4(address,(bytes32,bytes32,bytes32,((address,(address,address,bytes),(address,bytes32)[],(address,bytes32)[],bytes32),uint256,uint256,(address,bytes32[],bytes)[])[],bytes),((address,address,bytes),(address,bytes32[],bytes)[]))":"4ed39461","iStabullRouter()":"b8757e06","iTaskHash()":"93be095e","onTakeOrders2(address,address,bytes32,bytes32,bytes)":"691f9ed7","supportsInterface(bytes4)":"01ffc9a7"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"orderBook\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"contract IInterpreterV4\",\"name\":\"interpreter\",\"type\":\"address\"},{\"internalType\":\"contract IInterpreterStoreV3\",\"name\":\"store\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"bytecode\",\"type\":\"bytes\"}],\"internalType\":\"struct EvaluableV4\",\"name\":\"evaluable\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"context\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct SignedContextV1[]\",\"name\":\"signedContext\",\"type\":\"tuple[]\"}],\"internalType\":\"struct TaskV2\",\"name\":\"task\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"implementationData\",\"type\":\"bytes\"}],\"internalType\":\"struct OrderBookV5ArbConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"signedCoefficient\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"exponent\",\"type\":\"int256\"}],\"name\":\"CoefficientOverflow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"signedCoefficient\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"exponent\",\"type\":\"int256\"}],\"name\":\"ExponentOverflow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"signedCoefficient\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"exponent\",\"type\":\"int256\"}],\"name\":\"NegativeFixedDecimalConversion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoOrders\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongTask\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"orderBook\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"contract IInterpreterV4\",\"name\":\"interpreter\",\"type\":\"address\"},{\"internalType\":\"contract IInterpreterStoreV3\",\"name\":\"store\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"bytecode\",\"type\":\"bytes\"}],\"internalType\":\"struct EvaluableV4\",\"name\":\"evaluable\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"context\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct SignedContextV1[]\",\"name\":\"signedContext\",\"type\":\"tuple[]\"}],\"internalType\":\"struct TaskV2\",\"name\":\"task\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"implementationData\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct OrderBookV5ArbConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"Construct\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"contract IOrderBookV5\",\"name\":\"orderBook\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"Float\",\"name\":\"minimumInput\",\"type\":\"bytes32\"},{\"internalType\":\"Float\",\"name\":\"maximumInput\",\"type\":\"bytes32\"},{\"internalType\":\"Float\",\"name\":\"maximumIORatio\",\"type\":\"bytes32\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"contract IInterpreterV4\",\"name\":\"interpreter\",\"type\":\"address\"},{\"internalType\":\"contract IInterpreterStoreV3\",\"name\":\"store\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"bytecode\",\"type\":\"bytes\"}],\"internalType\":\"struct EvaluableV4\",\"name\":\"evaluable\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"vaultId\",\"type\":\"bytes32\"}],\"internalType\":\"struct IOV2[]\",\"name\":\"validInputs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"vaultId\",\"type\":\"bytes32\"}],\"internalType\":\"struct IOV2[]\",\"name\":\"validOutputs\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes32\",\"name\":\"nonce\",\"type\":\"bytes32\"}],\"internalType\":\"struct OrderV4\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"inputIOIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputIOIndex\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"context\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct SignedContextV1[]\",\"name\":\"signedContext\",\"type\":\"tuple[]\"}],\"internalType\":\"struct TakeOrderConfigV4[]\",\"name\":\"orders\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"struct TakeOrdersConfigV4\",\"name\":\"takeOrders\",\"type\":\"tuple\"},{\"components\":[{\"components\":[{\"internalType\":\"contract IInterpreterV4\",\"name\":\"interpreter\",\"type\":\"address\"},{\"internalType\":\"contract IInterpreterStoreV3\",\"name\":\"store\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"bytecode\",\"type\":\"bytes\"}],\"internalType\":\"struct EvaluableV4\",\"name\":\"evaluable\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"context\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"struct SignedContextV1[]\",\"name\":\"signedContext\",\"type\":\"tuple[]\"}],\"internalType\":\"struct TaskV2\",\"name\":\"task\",\"type\":\"tuple\"}],\"name\":\"arb4\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"iStabullRouter\",\"outputs\":[{\"internalType\":\"contract IStabullRouter\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"iTaskHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"outputToken\",\"type\":\"address\"},{\"internalType\":\"Float\",\"name\":\"inputAmountSent\",\"type\":\"bytes32\"},{\"internalType\":\"Float\",\"name\":\"totalOutputAmount\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"takeOrdersData\",\"type\":\"bytes\"}],\"name\":\"onTakeOrders2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"CoefficientOverflow(int256,int256)\":[{\"details\":\"Thrown when a coefficient overflows.\"}],\"ExponentOverflow(int256,int256)\":[{\"details\":\"Thrown when an exponent overflows.\"}],\"NegativeFixedDecimalConversion(int256,int256)\":[{\"details\":\"Thrown when attempting to convert a negative number to an unsigned fixed-point number.\"}]},\"kind\":\"dev\",\"methods\":{\"onTakeOrders2(address,address,bytes32,bytes32,bytes)\":{\"params\":{\"inputAmountSent\":\"The amount of `inputToken` that was sent to `IOrderBookV5OrderTaker`.\",\"inputToken\":\"The token that was sent to `IOrderBookV5OrderTaker`.\",\"outputToken\":\"The token that `IOrderBookV5` will attempt to pull from `IOrderBookV5OrderTaker` after this callback returns.\",\"takeOrdersData\":\"The data passed to `takeOrders` by the caller.\",\"totalOutputAmount\":\"The total amount of `outputToken` that `IOrderBookV5` will attempt to pull from `IOrderBookV5OrderTaker` after this callback returns.\"}},\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"errors\":{\"InvalidSignature(uint256)\":[{\"notice\":\"Thrown when the ith signature from a list of signed contexts is invalid.\"}],\"NoOrders()\":[{\"notice\":\"Thrown when take orders is called with no orders.\"}],\"WrongTask()\":[{\"notice\":\"Thrown when the task does not match the expected hash.\"}]},\"kind\":\"user\",\"methods\":{\"onTakeOrders2(address,address,bytes32,bytes32,bytes)\":{\"notice\":\"Called by `IOrderBookV5` when `takeOrders` is called with non-zero data, if it caused a non-zero input amount. I.e. if the order(s) taker received some tokens. Input and output directions are relative to the `IOrderBookV5OrderTaker` contract. If the order(s) taker had an active debt from a flash loan then that debt will be paid _before_ calculating any input amounts sent. i.e. the debt is deducted from the input amount before this callback is called.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/concrete/arb/RouteProcessorOrderBookV5ArbOrderTaker.sol\":\"RouteProcessorOrderBookV5ArbOrderTaker\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"appendCBOR\":false,\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[\":axelar-gmp-sdk-solidity/=lib/sushixswap-v2/lib/axelar-gmp-sdk-solidity/\",\":bytecode/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/bytecode/\",\":caller/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/caller/\",\":codegen/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/codegen/\",\":constants/=lib/rain.interpreter/src/lib/constants/\",\":deprecated/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/\",\":ds-test/=lib/sushixswap-v2/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/rain.interpreter/lib/rain.string/lib/openzeppelin-contracts/lib/erc4626-tests/\",\":eval/=lib/rain.interpreter/src/lib/eval/\",\":extern/=lib/rain.interpreter/src/lib/extern/\",\":forge-gas-snapshot/=lib/sushixswap-v2/lib/forge-gas-snapshot/src/\",\":forge-std/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/forge-std/src/\",\":integrity/=lib/rain.interpreter/src/lib/integrity/\",\":mut/=lib/rain.interpreter/lib/rain.string/src/lib/mut/\",\":ns/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/ns/\",\":op/=lib/rain.interpreter/src/lib/op/\",\":openzeppelin-contracts/=lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/\",\":openzeppelin/=lib/rain.interpreter/lib/rain.string/lib/openzeppelin-contracts/contracts/\",\":parse/=lib/rain.interpreter/src/lib/parse/\",\":rain.datacontract/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.float/lib/rain.datacontract/src/\",\":rain.interpreter.interface/=lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/\",\":rain.interpreter/=lib/rain.interpreter/src/\",\":rain.intorastring/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.intorastring/src/\",\":rain.lib.hash/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.lib.hash/src/\",\":rain.lib.memkv/=lib/rain.interpreter/lib/rain.lib.memkv/src/\",\":rain.lib.typecast/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.lib.typecast/src/\",\":rain.math.binary/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.binary/src/\",\":rain.math.fixedpoint/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.float/lib/rain.math.fixedpoint/src/\",\":rain.math.float/=lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/\",\":rain.math.saturating/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.float/lib/rain.math.fixedpoint/lib/rain.math.saturating/src/\",\":rain.metadata/=lib/rain.interpreter/lib/rain.metadata/src/\",\":rain.orderbook.interface/=lib/rain.orderbook.interface/src/\",\":rain.sol.codegen/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.sol.codegen/src/\",\":rain.solmem/=lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/\",\":rain.string/=lib/rain.interpreter/lib/rain.string/src/\",\":rain.tofu.erc20-decimals/=lib/rain.tofu.erc20-decimals/src/\",\":sol.lib.binmaskflag/=lib/rain.interpreter/lib/sol.lib.binmaskflag/src/\",\":state/=lib/rain.interpreter/src/lib/state/\",\":sushixswap-v2/=lib/sushixswap-v2/\"]},\"sources\":{\"lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.lib.hash/src/LibHashNoAlloc.sol\":{\"keccak256\":\"0x1153c2d2ec53adca83c81c37ac958aab8b4d31e0e01f64f5189b1783375c0347\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://79d10d5165cf0d5cc8b28b76613fc114e74c33fcc2d5632f7e284dace2247927\",\"dweb:/ipfs/QmZEt4BQ6xsfiFNBQ55GoQq8Ats3Hb1v2hPFEWPDeqKrTv\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol\":{\"keccak256\":\"0x0705a4b1b86d7b0bd8432118f226ba139c44b9dcaba0a6eafba2dd7d0639c544\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c45b821ef9e882e57c256697a152e108f0f2ad6997609af8904cae99c9bd422e\",\"dweb:/ipfs/QmRKCJW6jjzR5UYZcLpGnhEJ75UVbH6EHkEa49sWx2SKng\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol\":{\"keccak256\":\"0xa535a5df777d44e945dd24aa43a11e44b024140fc340ad0dfe42acf4002aade1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://41319e7f621f2dc3733511332c4fd032f8e32ad2aa7fd6f665c19741d9941a34\",\"dweb:/ipfs/QmcYR3bd862GD1Bc7jwrU9bGxrhUu5na1oP964bDCu2id1\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://bd39944e8fc06be6dbe2dd1d8449b5336e23c6a7ba3e8e9ae5ae0f37f35283f5\",\"dweb:/ipfs/QmPV3FGYjVwvKSgAXKUN3r9T9GwniZz83CxBpM7vyj2G53\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5a376d3dda2cb70536c0a45c208b29b34ac560c4cb4f513a42079f96ba47d2dd\",\"dweb:/ipfs/QmZQg6gn1sUpM8wHzwNvSnihumUCAhxD119MpXeKp8B9s8\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol\":{\"keccak256\":\"0xb264c03a3442eb37a68ad620cefd1182766b58bee6cec40343480392d6b14d69\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://28879d01fd22c07b44f006612775f8577defbe459cb01685c5e25cd518c91a71\",\"dweb:/ipfs/QmVgfkwv2Fxw6hhTcDUZhE7NkoSKjab3ipM7UaRbt6uXb5\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol\":{\"keccak256\":\"0xabefac93435967b4d36a4fabcbdbb918d1f0b7ae3c3d85bc30923b326c927ed1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9d213d3befca47da33f6db0310826bcdb148299805c10d77175ecfe1d06a9a68\",\"dweb:/ipfs/QmRgCn6SP1hbBkExUADFuDo8xkT4UU47yjNF5FhCeRbQmS\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2455248c8ddd9cc6a7af76a13973cddf222072427e7b0e2a7d1aff345145e931\",\"dweb:/ipfs/QmfYjnjRbWqYpuxurqveE6HtzsY1Xx323J428AKQgtBJZm\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/Strings.sol\":{\"keccak256\":\"0x3088eb2868e8d13d89d16670b5f8612c4ab9ff8956272837d8e90106c59c14a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b81d9ff6559ea5c47fc573e17ece6d9ba5d6839e213e6ebc3b4c5c8fe4199d7f\",\"dweb:/ipfs/QmPCW1bFisUzJkyjroY3yipwfism9RRCigCcK1hbXtVM8n\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0x809bc3edb4bcbef8263fa616c1b60ee0004b50a8a1bfa164d8f57fd31f520c58\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8b93a1e39a4a19eba1600b92c96f435442db88cac91e315c8291547a2a7bcfe2\",\"dweb:/ipfs/QmTm34KVe6uZBZwq8dZDNWwPcm24qBJdxqL3rPxBJ4LrMv\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol\":{\"keccak256\":\"0x3af3ca86df39aac39a0514c84459d691434a108d2151c8ce9d69f32e315cab80\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://77d1f1cf302cd5e1dfbbb4ce3b281b28e8c52942d4319fce43df2e1b6f02a52d\",\"dweb:/ipfs/QmT6ZXStmK3Knhh9BokeVHQ9HXTBZNgL3Eb1ar1cYg1hWy\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol\":{\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fb0048dee081f6fffa5f74afc3fb328483c2a30504e94a0ddd2a5114d731ec4d\",\"dweb:/ipfs/QmZptt1nmYoA5SgjwnSgWqgUSDgm4q52Yos3xhnMv3MV43\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://be161e54f24e5c6fae81a12db1a8ae87bc5ae1b0ddc805d82a1440a68455088f\",\"dweb:/ipfs/QmP7C3CHdY9urF4dEMb9wmsp1wMxHF6nhA2yQE5SKiPAdy\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/math/Math.sol\":{\"keccak256\":\"0xe4455ac1eb7fc497bb7402579e7b4d64d928b846fce7d2b6fde06d366f21c2b3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cc8841b3cd48ad125e2f46323c8bad3aa0e88e399ec62acb9e57efa7e7c8058c\",\"dweb:/ipfs/QmSqE4mXHA2BXW58deDbXE8MTcsL5JSKNDbm23sVQxRLPS\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol\":{\"keccak256\":\"0xf92515413956f529d95977adc9b0567d583c6203fc31ab1c23824c35187e3ddc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c50fcc459e49a9858b6d8ad5f911295cb7c9ab57567845a250bf0153f84a95c7\",\"dweb:/ipfs/QmcEW85JRzvDkQggxiBBLVAasXWdkhEysqypj9EaB6H2g6\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/error/ErrDecimalFloat.sol\":{\"keccak256\":\"0x3c9e3f5e6b78877add52f397e2cf452e8a1afe6b9e630fc7bbc7c2d6704d07d9\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://9840b88bf5143a94f8e7779390b025dda83530090be3503e110aa2584250c6e4\",\"dweb:/ipfs/QmemaALnbRKFChq5Ec1p4xdar5rDqEvdbQwGb2vzMVWhK9\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/lib/LibDecimalFloat.sol\":{\"keccak256\":\"0x5c8820a79da0ac3c8558ae65c8b3b2b4579326755a4914a243f2475c1159b2aa\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://edc7ddd33798964f19aa9183fa0366321f93ab03171ba334192f65bd71a1a53d\",\"dweb:/ipfs/QmYKAKopDLGMWCfTVhwhF3vCGw6wXveKX1uTtxCyvycNkL\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/lib/implementation/LibDecimalFloatImplementation.sol\":{\"keccak256\":\"0x182d010eee786cfa19ad44e215332c4e6fd4e9310da3e61ebd17a0309307d6b6\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://1206a9557d6410c30ec82f02d44d3e857d7aabf46d607ee08bf415af14f8a799\",\"dweb:/ipfs/Qmbygfmw9K8YVQdEsNEkkHxTbTiuuDgWt7yB6gMwoYGBcp\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/lib/table/LibLogTable.sol\":{\"keccak256\":\"0x412629a161febf0dc9c3bae0cc9fe0b8de8774d37c5f3afde2e2312478d96a98\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://c8da5302117961caad328e80cb28296ea71aadbc291312e37d3db079d84a9777\",\"dweb:/ipfs/QmWYzpex1Xrnjf3QM68n6mGFQ4KxE53fUUyDjwE3zNrtok\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/error/ErrBytes.sol\":{\"keccak256\":\"0xdec97437eeba42f5950dc52f89caac433bc11a56a4e14a0f67a521821600c4b6\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://72b96a4ed0d34dab653df0e6eb19d77b3e1c691b8e35543f6f32ae6a44c6312e\",\"dweb:/ipfs/QmNrwwf3La4D25DudigRedu2c7xfx8k7bEzHFVZfpRu3se\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/error/ErrUint256Array.sol\":{\"keccak256\":\"0x57b7a7a5cbc2fc97200130e84fde3a8afc14e0729040b14670dacc7f63c3ac5f\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://4e7c7ce525e882db437b488b590fae6a817b282f88d76eb4f56986b549815e57\",\"dweb:/ipfs/QmajzM26fsaFtaAnm5cg1FZrD6N2wkLJHCxa7Atx5x6iAB\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/lib/LibBytes.sol\":{\"keccak256\":\"0x6497d17390179a62820805d18a2cf2cdfddbe4990df783bde11cbf82e414fd0e\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://54e8ed63c566d374ca2d89e8109c41267f7ca661e85570c6c7d51193aaca128b\",\"dweb:/ipfs/Qmd6LoUZqg7TbeAx2auk5UkimyMiK4a9GsVMvDeqDRZF3M\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/lib/LibMemCpy.sol\":{\"keccak256\":\"0xf0918be203ec6bba9beb5d58b53d4ae66a8d07764ad872518cbbd39fb7eee77e\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://6a71e16de54788fc3d8d84e4866582aa9955dad598c6131b59e2348acaa9596c\",\"dweb:/ipfs/QmSNZ8VCw8zDBNCQ3ovevNqDQmXE8kcvctEXkggunJJe2x\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/lib/LibPointer.sol\":{\"keccak256\":\"0x3fc6ff807b57b681e32229380e3eda57107a1ada8dc2c1270daa84c9fca5addc\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://a82b17ddc1db163ec548648c83dd5bb2f9f4441559452933f424e0a8dff48e57\",\"dweb:/ipfs/QmdKoRbEAPxBRHJWWRwjh9Yrps1QXcJuX5mJmua8nvnq7B\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/lib/LibUint256Array.sol\":{\"keccak256\":\"0xa3aecfdc5acd9762e80c09cb3993fc5f13f276d1221452856d1d29e8ff2b2b72\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://d8c02db51b5cf8acd99091b59c255a17be0f47d818d4e5d372ff2c6fd00f2ede\",\"dweb:/ipfs/QmXoEUdXzQkCLbcbFEvKtipdPrBhjnrbauHMtqug2j8RZx\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/error/ErrBytecode.sol\":{\"keccak256\":\"0x4d740b62c6e81ffdb25a42c72a5bd5ea945659df1bc38510b4e95a9cd3bfe8bb\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://aa05c6e63a9bd9dd722d3824b2ae376d5237c81a189e0e42bf9a1ba33da919d3\",\"dweb:/ipfs/QmPLZtsKPrC9nLwk1jqw7LwwvsXAkxomrtUQLrhiQNWubC\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/IInterpreterCallerV3.sol\":{\"keccak256\":\"0x234691f341e7d7f9123bd6be9ce02d4e38ecccc599899f83345e760cdf0d6bb1\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://3d53753fca93e9e57129ca68080904b7336d5a798959dc462851d9bdcdd460d6\",\"dweb:/ipfs/Qmd4HhCSHHpsCFZpAFcXQbUuqCC9zHp4EPwu7syWCetbNW\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/IInterpreterStoreV2.sol\":{\"keccak256\":\"0x89b7dfa624962983c42da404fc8653daa29e793a60f11a2d9c8a9cf34caaf71a\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://10dcc56124d4a054ad13227e6098b7ceda11bbeccd8bb38d1e57da542285f72d\",\"dweb:/ipfs/QmUSgcm3Hpifk4GyjGMssJfo2Pea9dMm9sP4AzyzGfVA5c\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/IInterpreterV3.sol\":{\"keccak256\":\"0xf7515e68c4ad0218beafff4f59e21bbaf6c1268499515e4b9c28326440c574e1\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://dc3ddb0928de02c43930be791cf3b9c4ab1f2aba2d8acc768f5c746b2e69fd20\",\"dweb:/ipfs/QmRyACpHRo4TQpmpuioQ43oMMaRTSiEt8MMuYzCiwZCGXL\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/IParserV2.sol\":{\"keccak256\":\"0x84b444c476b512c70c6ca40867f85597966f932f2bb0db77fe2a5416298cb3e3\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://df1ec34672cbe90ae3c9cbbf43d399e6a2a5b12dfb35d23f05d14ef7205225e2\",\"dweb:/ipfs/QmPPHNfVKkUSDxT2nrWLbGg4xjJZwmx4598EqTayZG4yqw\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IExpressionDeployerV1.sol\":{\"keccak256\":\"0xc0afd50701cd68eef984a63862bd6a10552d704cca6e10f06d19d920b0777c98\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://cd3cbfa9159ceed8871f46f62c7ea235ad8537d3c6c1c004152ebf5d2d597346\",\"dweb:/ipfs/QmPSAJXAcmDeK9Qy6s2dXdeu4GJ62FKWa69VBo4ioCPcJ9\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IExpressionDeployerV2.sol\":{\"keccak256\":\"0x368ace8d0f82832f08caf264e4194647b9777c0d4a0f22d88236b30c1e4c8a63\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://9c8a2141fcd76d6308156777b0a9e5a4f7f07fb3693461e2c12f07e4d8c87130\",\"dweb:/ipfs/QmPnhPz6sXzh5xBGZobAPY2WJTgvQDiYWRFKavscSPu7T5\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IExpressionDeployerV3.sol\":{\"keccak256\":\"0x6f6b03c0f8e37ebe4275e0d27242754c7be815ff091ad0931a7be21ab11de628\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://1f200079a3689e0d0c8efb97040737a2b4113a82f0df5d8319af36d9ad5d8b97\",\"dweb:/ipfs/QmXFzXZasmD9D7pAYC5wBtB748TZajy69V5tmSEXRd1VZk\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterCallerV1.sol\":{\"keccak256\":\"0xc01bc48e2479cab07fc799e26c3790c8cf97acc1f0f490c8f456f554d239a505\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://2981aa2eae0d414bc8ad4105bedb05026cfdad7e6af8f23805dba4835ae9fd8a\",\"dweb:/ipfs/QmQRKi5nmatC1UM2sNta9giuJX3xvvLAD5pmCeAsVWF4hF\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterCallerV2.sol\":{\"keccak256\":\"0x62c7149e3d28cd9b67d7eed183c4e59cf300689dd5cc363b011cb2cf32c1200d\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://52cf991b2dc9581222520c32cac224f6936c75183e4c6c16fafa4450a05c0de0\",\"dweb:/ipfs/QmZ7fiZYjnDhNnFXYCXC9iSYs8WAAwmsVxBd5XDA1tPPah\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterStoreV1.sol\":{\"keccak256\":\"0x7d2bc86fefbe372fc64381b320244fe9dbda1816867f3040c5bb3951869fe6a7\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://90c371494080129d5acd2bc52d092fc5cfe559147f7fc855ed01e62a7837f21e\",\"dweb:/ipfs/QmcNtPDuTxic8zqRFXf1ba6FJKmQXguxiDUY4E7wjyVwU5\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterV1.sol\":{\"keccak256\":\"0xe0b94c771a7b6aa05388b4db6e238e36a4653cbfdbd3e54bbcaa7a97fc9491f4\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://59887a7f2ef60669906c5e70831ac0c9a7345313b04efb306235280f85e1db73\",\"dweb:/ipfs/QmP6Ny9m3sPCP65UmgGGpucSMgVAoDv6qURqyxUE95VU5Q\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterV2.sol\":{\"keccak256\":\"0xa785ce2ac17059933b74aa3c8bd51321694ba8ddf27f2767ef99ea002faae1c6\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://130555df49552cf6865c4e82d6e67dd115151de2cd2161fb138849992d6a7a82\",\"dweb:/ipfs/QmRvrAGrkk3zgiG9Rox7m9wwzJL6B8ZcQAQvJpYKbvXvTS\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IParserV1.sol\":{\"keccak256\":\"0x4f6a9e028942cebebfc84328193f1d31807aac292d9b82e2df489064aa913070\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://54073f63db1f652571472cb2d07de297772c2420e1571a0cb9e0a805ee4347e7\",\"dweb:/ipfs/QmXRqBreJvC8MQd5zLNgmPUdfFa4WD6gSoxvD8hecycux4\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/unstable/IInterpreterCallerV4.sol\":{\"keccak256\":\"0xedf1a8c0814b72b278a60c6ae7867df832628b8752d53fbd53598daf6f50ddf0\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://e1ab9686ad00c7c71146d6bd696b370b563664979682a77262eac61bb1d1fc44\",\"dweb:/ipfs/QmeNHknab5XJnwxNF6HrMk18Xnv9ycsj1NKsVSmYBJkLWA\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/unstable/IInterpreterStoreV3.sol\":{\"keccak256\":\"0xbfa8a7c8920c8aeeb821544d5dfcaae533fa4ddf5939f7c68fcc1df048e24756\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://7f46c0fde6d5adb57e0459a5864103c33191452b0656316bd4687ab32aa8c77d\",\"dweb:/ipfs/QmdCcxQAkK3RvDDuZpdZo4tr6oUf6PDhptfjr2dDTjsd4U\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/unstable/IInterpreterV4.sol\":{\"keccak256\":\"0x21328db6613f5d669637e97fefa1c17c4975e3af195e66a3ee538bd85c4a2ec4\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://1cca4fca2a64b39230242f7938ef25368753791c40a9e184755eb810c8b64054\",\"dweb:/ipfs/QmZMJ2EMX9wcfnD1WDpTrknRjGA3okymAPLw1Fbrqgz7N9\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/bytecode/LibBytecode.sol\":{\"keccak256\":\"0x4d4554be5092bb334a78064679423e9a466767a5ba5ad38669bbf2c70cbcddcf\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://3fdc83b600be2d3fa782ae3ecd1f3be3d3c262eef9d4d45370eea2d8c990b160\",\"dweb:/ipfs/QmZTzKXNs8Jsr1HRcfx5Tb3Pem3NqmwVnjiLdoiV45gGSA\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/caller/LibContext.sol\":{\"keccak256\":\"0xe9199fe71b30ba63e33b374a9a5145393814ba83b4617e19124db7d057d04bba\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://6eed183238aba53bcec54b9f952ff25cf01814dfa6f09da9754e7a08738432b7\",\"dweb:/ipfs/QmdkRkBBpNWuVHqzoPjy1TUA1MVjaD6RWRFefpYcWnNLFb\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/caller/LibEvaluable.sol\":{\"keccak256\":\"0xc6a557258f287f672de835a407740ca614cebe29e7f0ad810d8299142098346a\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://6c7c676affa52e8cf8397f5e1f21928df03fc76cde78800f1c93a6faea5a2ab0\",\"dweb:/ipfs/QmVNrKyn5v3DnRj9p6MVEhu8Z9mpYVHL3nfLXnwwrVBeXU\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/deprecated/caller/LibEncodedDispatch.sol\":{\"keccak256\":\"0x9d509dc03442c02d9fc03beb66b1481210f0d6c53f640ee3de06cea93cfa6add\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://dc089b82823cc8e7c65a2c65e31150c74441b10187884c40ad6a992c627e4b04\",\"dweb:/ipfs/QmdA1hdC7mgC4cubyLF4sUt1G2ux7wVLNFye4KKcrg79fa\"]},\"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/ns/LibNamespace.sol\":{\"keccak256\":\"0xd621d3e5f8b404309ad5d841a3658248e979c1bd59876be3afa7aa0595b4c0e6\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://801fa302f49f3734dd5cc6221dd25f73591ac8feae47351c18e30a98a4ae0ce1\",\"dweb:/ipfs/QmbwXbTSMZ4u6ZsyfseBx79PeHNAWocNHXpgnaPVmLZM38\"]},\"lib/rain.orderbook.interface/src/interface/IOrderBookV4.sol\":{\"keccak256\":\"0x715c5211361bd469a9ec916710611536d087ae5630a3fc3f80e9802ec43c4596\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://c61433f7de82ac5fbd752470aa1b9358dc70455ba85be87a9056509188f5db21\",\"dweb:/ipfs/QmaGvPxe4xpqkVMdq9mo2moJyBHB9f8wTkcxZotk7tevVH\"]},\"lib/rain.orderbook.interface/src/interface/deprecated/v2/IOrderBookV2.sol\":{\"keccak256\":\"0x30c528f1772e9593b5329f1458cab4cce3510a2ccca01696b506af177fffd786\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://9f53c14e5aaab2cd2fbf5b39d07c59acfdc09aff3476345816c2635de2cdd5d3\",\"dweb:/ipfs/QmaomXfmDKdoeYwbMe9cy5anx4fDEMtP4W9Rre5s5DZVE6\"]},\"lib/rain.orderbook.interface/src/interface/deprecated/v3/IOrderBookV3.sol\":{\"keccak256\":\"0xdca3fd0c6106ab98d08682e63e433b74250d1f01e646a5908c97183d9b25130b\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://0f986a8388275a4144068981aa628e46bff221c2d27a3ad597a9c5fc2d4fcb09\",\"dweb:/ipfs/QmR2pxkpY4ddhLb7jdoNAVSJwYHokyGpn5Tzg3Q7YnGYgW\"]},\"lib/rain.orderbook.interface/src/interface/ierc3156/IERC3156FlashBorrower.sol\":{\"keccak256\":\"0xdcd81b1110e9c3c91715ac90aef1da70066bcaba8aeb3dc23df979f7f87644f9\",\"license\":\"CC0-1.0\",\"urls\":[\"bzz-raw://4572efaeb9eb30ad9b766b80cb2a8101a2cec0c9e8c78c7696f4aae710c8e2c9\",\"dweb:/ipfs/QmVsz1gtqWfxTAbsoLPvZBe6PBVXqaWNx6nu7RHr2ghLuK\"]},\"lib/rain.orderbook.interface/src/interface/ierc3156/IERC3156FlashLender.sol\":{\"keccak256\":\"0x119c477281a6ec109e9c729a254b39d7ccc9a9f5baa82fa28d0fa1e3bd2b6ae8\",\"license\":\"CC0-1.0\",\"urls\":[\"bzz-raw://19ec8289a123459659dca0389a650ca6bf6bc12d925ad7a3e61f0b1bfe68d1b6\",\"dweb:/ipfs/QmRZ9U5ECovPFmbRaBTauFjjVQcvPA7VQL7S1zJVEBTMD5\"]},\"lib/rain.orderbook.interface/src/interface/unstable/IOrderBookV5.sol\":{\"keccak256\":\"0x22e5d686e94d1f38d4361d90197ac606eaacad8dde383c1511707347744bb181\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://175376edb09374551786b57604d04be0b89d2b9aeacb5c6307ce7efb37e41b30\",\"dweb:/ipfs/QmeSjgcBe6SDr5Vbo3QZGsL2NArsUSqPDFSfXiVGi8ftWu\"]},\"lib/rain.orderbook.interface/src/interface/unstable/IOrderBookV5ArbOrderTaker.sol\":{\"keccak256\":\"0xf49109c3736342baac6531dfc53136f7a58e7f3013b8dc2bff6b5a6c7a6922e1\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://a73b0ef285322930745661c634e73c42d262eb741bc11037163808c3e0cfd388\",\"dweb:/ipfs/QmbuYQRczLb1NSKh7j8JqspLTRtusRDQW29oaUtxof6r2A\"]},\"lib/rain.orderbook.interface/src/interface/unstable/IOrderBookV5OrderTaker.sol\":{\"keccak256\":\"0x76ccb34468d99c23ea5f7361c87741989e3938dc5eb27dbc502f8546d14a9d29\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://1b26eebc3a1bb35684273836a22f56e8fd87e2dd05f6cefe18742834a90a7970\",\"dweb:/ipfs/QmYaB45rjqghoQfcvrUBoScrJkDnM4jGwdAkM5UZtLfusM\"]},\"lib/rain.tofu.erc20-decimals/src/interface/ITOFUTokenDecimals.sol\":{\"keccak256\":\"0xff728b82d787191dc32f7dac385baa1e194d313c84979b90934e6b8fd06ddbc5\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://e789fb5fcb3396d81fa487c907486b9ba7d33312502b676e43816f777e0379fd\",\"dweb:/ipfs/Qme1evJCUVHVpPteVvgwW84fNAJwLKfVi5xmJjNrhKEziR\"]},\"lib/rain.tofu.erc20-decimals/src/lib/LibTOFUTokenDecimals.sol\":{\"keccak256\":\"0xc76d8a73006c59a80996514333553c8cf67620e725a03fb1ba4be75f2241c3bb\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://ef559d0939d8378db26d4cfa8c4342494135afe360a1884e3ca90502266bb77c\",\"dweb:/ipfs/QmS2B4VD1CdKsou7Hxsk1cYp3cmNiTiQdcihn5j5qP7Yw5\"]},\"lib/sushixswap-v2/src/interfaces/IRouteProcessor.sol\":{\"keccak256\":\"0x5b2289c992f34dd25943db3cbc27ece8b0a1addeb2631f812e7834b7ae3eac37\",\"license\":\"GPL-3.0-or-later\",\"urls\":[\"bzz-raw://f21522058b7fe3c18d2353b06a5ddbf2b62d2aceebf7dd6dfdc51b081452bb3f\",\"dweb:/ipfs/QmVkicGnNWgnX1RfXJWPpQaAPbiAQfFwGWigbPi1wu2WiT\"]},\"src/abstract/OrderBookV5ArbCommon.sol\":{\"keccak256\":\"0xdcf58e56fb28af2a079ee70a0e05e23f04fe05688d5c4a421169388b4678a498\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://3368ca28ddea108ff2268aa4cac6026cfe3e6d76a7fe2e08e3c45c710601e888\",\"dweb:/ipfs/QmS6TTjG6kbYVs7soCygp9AiKN49Lrp7aDrQTjhBssTtgw\"]},\"src/abstract/OrderBookV5ArbOrderTaker.sol\":{\"keccak256\":\"0xd37da11daba7e13a9ad6f0dc8365360cc5bc25a587c4c2e8ce61ef680d768391\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://b6a7e1ce0f6080ed52c6c391406e2a4afae51308ccf22fe71243cc8212cee30c\",\"dweb:/ipfs/QmUdgd3iXYXorY2uKyUTbiKJdR4eJjj7yFezCShSsxKVeG\"]},\"src/concrete/arb/RouteProcessorOrderBookV5ArbOrderTaker.sol\":{\"keccak256\":\"0xb4890fc6d6efb23f0a3efdc9dc6aecc4433d4b2f86d1fe1fe84878e67ff738e9\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://dd8dd96f30251937c0c7597eaa8bb2c930f9b98c7cf0134c0270a21c0e23dce9\",\"dweb:/ipfs/QmZVZghmpViQZVDGYTWzvrvaqqpmkNDR8HwjQQydpTTuL8\"]},\"src/lib/LibOrderBook.sol\":{\"keccak256\":\"0x85084b3b250dadcaedf66a20193c13cb0acfa134a340b6938c2390eb3ca0e4ad\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://34beb9f1fbd20b7d20cf43c5130595b856285c3cf5a5622a25b8a182214d84a4\",\"dweb:/ipfs/QmX1ikfbzJSuQ7xkPzsQzW5gEizVA2jrLUgtKjPTrXfnh2\"]},\"src/lib/LibOrderBookArb.sol\":{\"keccak256\":\"0x63231331baf261d7a038b62789d55d9b012eacbd322c525d143ea5a8b302a94f\",\"license\":\"LicenseRef-DCL-1.0\",\"urls\":[\"bzz-raw://7cf33f078a10304ceec5ac2a6b3e0e1e0ff9df1e55f7ea202228ddb0b03c507e\",\"dweb:/ipfs/QmQPrfUeesGp5ipt5GyjPhkW4mwcrL6SpuHpJS9gUXSJEH\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.25+commit.b61c2a91"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"struct OrderBookV5ArbConfig","name":"config","type":"tuple","components":[{"internalType":"address","name":"orderBook","type":"address"},{"internalType":"struct TaskV2","name":"task","type":"tuple","components":[{"internalType":"struct EvaluableV4","name":"evaluable","type":"tuple","components":[{"internalType":"contract IInterpreterV4","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV3","name":"store","type":"address"},{"internalType":"bytes","name":"bytecode","type":"bytes"}]},{"internalType":"struct SignedContextV1[]","name":"signedContext","type":"tuple[]","components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes32[]","name":"context","type":"bytes32[]"},{"internalType":"bytes","name":"signature","type":"bytes"}]}]},{"internalType":"bytes","name":"implementationData","type":"bytes"}]}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"int256","name":"signedCoefficient","type":"int256"},{"internalType":"int256","name":"exponent","type":"int256"}],"type":"error","name":"CoefficientOverflow"},{"inputs":[{"internalType":"int256","name":"signedCoefficient","type":"int256"},{"internalType":"int256","name":"exponent","type":"int256"}],"type":"error","name":"ExponentOverflow"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"type":"error","name":"InvalidSignature"},{"inputs":[{"internalType":"int256","name":"signedCoefficient","type":"int256"},{"internalType":"int256","name":"exponent","type":"int256"}],"type":"error","name":"NegativeFixedDecimalConversion"},{"inputs":[],"type":"error","name":"NoOrders"},{"inputs":[],"type":"error","name":"WrongTask"},{"inputs":[{"internalType":"address","name":"sender","type":"address","indexed":false},{"internalType":"struct OrderBookV5ArbConfig","name":"config","type":"tuple","components":[{"internalType":"address","name":"orderBook","type":"address"},{"internalType":"struct TaskV2","name":"task","type":"tuple","components":[{"internalType":"struct EvaluableV4","name":"evaluable","type":"tuple","components":[{"internalType":"contract IInterpreterV4","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV3","name":"store","type":"address"},{"internalType":"bytes","name":"bytecode","type":"bytes"}]},{"internalType":"struct SignedContextV1[]","name":"signedContext","type":"tuple[]","components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes32[]","name":"context","type":"bytes32[]"},{"internalType":"bytes","name":"signature","type":"bytes"}]}]},{"internalType":"bytes","name":"implementationData","type":"bytes"}],"indexed":false}],"type":"event","name":"Construct","anonymous":false},{"inputs":[],"stateMutability":"nonpayable","type":"fallback"},{"inputs":[{"internalType":"contract IOrderBookV5","name":"orderBook","type":"address"},{"internalType":"struct TakeOrdersConfigV4","name":"takeOrders","type":"tuple","components":[{"internalType":"Float","name":"minimumInput","type":"bytes32"},{"internalType":"Float","name":"maximumInput","type":"bytes32"},{"internalType":"Float","name":"maximumIORatio","type":"bytes32"},{"internalType":"struct TakeOrderConfigV4[]","name":"orders","type":"tuple[]","components":[{"internalType":"struct OrderV4","name":"order","type":"tuple","components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"struct EvaluableV4","name":"evaluable","type":"tuple","components":[{"internalType":"contract IInterpreterV4","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV3","name":"store","type":"address"},{"internalType":"bytes","name":"bytecode","type":"bytes"}]},{"internalType":"struct IOV2[]","name":"validInputs","type":"tuple[]","components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"vaultId","type":"bytes32"}]},{"internalType":"struct IOV2[]","name":"validOutputs","type":"tuple[]","components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"vaultId","type":"bytes32"}]},{"internalType":"bytes32","name":"nonce","type":"bytes32"}]},{"internalType":"uint256","name":"inputIOIndex","type":"uint256"},{"internalType":"uint256","name":"outputIOIndex","type":"uint256"},{"internalType":"struct SignedContextV1[]","name":"signedContext","type":"tuple[]","components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes32[]","name":"context","type":"bytes32[]"},{"internalType":"bytes","name":"signature","type":"bytes"}]}]},{"internalType":"bytes","name":"data","type":"bytes"}]},{"internalType":"struct TaskV2","name":"task","type":"tuple","components":[{"internalType":"struct EvaluableV4","name":"evaluable","type":"tuple","components":[{"internalType":"contract IInterpreterV4","name":"interpreter","type":"address"},{"internalType":"contract IInterpreterStoreV3","name":"store","type":"address"},{"internalType":"bytes","name":"bytecode","type":"bytes"}]},{"internalType":"struct SignedContextV1[]","name":"signedContext","type":"tuple[]","components":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes32[]","name":"context","type":"bytes32[]"},{"internalType":"bytes","name":"signature","type":"bytes"}]}]}],"stateMutability":"payable","type":"function","name":"arb4"},{"inputs":[],"stateMutability":"view","type":"function","name":"iStabullRouter","outputs":[{"internalType":"contract IStabullRouter","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"iTaskHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"Float","name":"inputAmountSent","type":"bytes32"},{"internalType":"Float","name":"totalOutputAmount","type":"bytes32"},{"internalType":"bytes","name":"takeOrdersData","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"onTakeOrders2"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"stateMutability":"view","type":"function","name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"onTakeOrders2(address,address,bytes32,bytes32,bytes)":{"params":{"inputAmountSent":"The amount of `inputToken` that was sent to `IOrderBookV5OrderTaker`.","inputToken":"The token that was sent to `IOrderBookV5OrderTaker`.","outputToken":"The token that `IOrderBookV5` will attempt to pull from `IOrderBookV5OrderTaker` after this callback returns.","takeOrdersData":"The data passed to `takeOrders` by the caller.","totalOutputAmount":"The total amount of `outputToken` that `IOrderBookV5` will attempt to pull from `IOrderBookV5OrderTaker` after this callback returns."}},"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"userdoc":{"kind":"user","methods":{"onTakeOrders2(address,address,bytes32,bytes32,bytes)":{"notice":"Called by `IOrderBookV5` when `takeOrders` is called with non-zero data, if it caused a non-zero input amount. I.e. if the order(s) taker received some tokens. Input and output directions are relative to the `IOrderBookV5OrderTaker` contract. If the order(s) taker had an active debt from a flash loan then that debt will be paid _before_ calculating any input amounts sent. i.e. the debt is deducted from the input amount before this callback is called."}},"version":1}},"settings":{"remappings":["axelar-gmp-sdk-solidity/=lib/sushixswap-v2/lib/axelar-gmp-sdk-solidity/","bytecode/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/bytecode/","caller/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/caller/","codegen/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/codegen/","constants/=lib/rain.interpreter/src/lib/constants/","deprecated/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/","ds-test/=lib/sushixswap-v2/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/rain.interpreter/lib/rain.string/lib/openzeppelin-contracts/lib/erc4626-tests/","eval/=lib/rain.interpreter/src/lib/eval/","extern/=lib/rain.interpreter/src/lib/extern/","forge-gas-snapshot/=lib/sushixswap-v2/lib/forge-gas-snapshot/src/","forge-std/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/forge-std/src/","integrity/=lib/rain.interpreter/src/lib/integrity/","mut/=lib/rain.interpreter/lib/rain.string/src/lib/mut/","ns/=lib/rain.interpreter/lib/rain.interpreter.interface/src/lib/ns/","op/=lib/rain.interpreter/src/lib/op/","openzeppelin-contracts/=lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/","openzeppelin/=lib/rain.interpreter/lib/rain.string/lib/openzeppelin-contracts/contracts/","parse/=lib/rain.interpreter/src/lib/parse/","rain.datacontract/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.float/lib/rain.datacontract/src/","rain.interpreter.interface/=lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/","rain.interpreter/=lib/rain.interpreter/src/","rain.intorastring/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.intorastring/src/","rain.lib.hash/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.lib.hash/src/","rain.lib.memkv/=lib/rain.interpreter/lib/rain.lib.memkv/src/","rain.lib.typecast/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.lib.typecast/src/","rain.math.binary/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.binary/src/","rain.math.fixedpoint/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.float/lib/rain.math.fixedpoint/src/","rain.math.float/=lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/","rain.math.saturating/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.float/lib/rain.math.fixedpoint/lib/rain.math.saturating/src/","rain.metadata/=lib/rain.interpreter/lib/rain.metadata/src/","rain.orderbook.interface/=lib/rain.orderbook.interface/src/","rain.sol.codegen/=lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.sol.codegen/src/","rain.solmem/=lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/","rain.string/=lib/rain.interpreter/lib/rain.string/src/","rain.tofu.erc20-decimals/=lib/rain.tofu.erc20-decimals/src/","sol.lib.binmaskflag/=lib/rain.interpreter/lib/sol.lib.binmaskflag/src/","state/=lib/rain.interpreter/src/lib/state/","sushixswap-v2/=lib/sushixswap-v2/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"bytecodeHash":"none","appendCBOR":false},"compilationTarget":{"src/concrete/arb/RouteProcessorOrderBookV5ArbOrderTaker.sol":"RouteProcessorOrderBookV5ArbOrderTaker"},"evmVersion":"paris","libraries":{}},"sources":{"lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.lib.hash/src/LibHashNoAlloc.sol":{"keccak256":"0x1153c2d2ec53adca83c81c37ac958aab8b4d31e0e01f64f5189b1783375c0347","urls":["bzz-raw://79d10d5165cf0d5cc8b28b76613fc114e74c33fcc2d5632f7e284dace2247927","dweb:/ipfs/QmZEt4BQ6xsfiFNBQ55GoQq8Ats3Hb1v2hPFEWPDeqKrTv"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol":{"keccak256":"0x0705a4b1b86d7b0bd8432118f226ba139c44b9dcaba0a6eafba2dd7d0639c544","urls":["bzz-raw://c45b821ef9e882e57c256697a152e108f0f2ad6997609af8904cae99c9bd422e","dweb:/ipfs/QmRKCJW6jjzR5UYZcLpGnhEJ75UVbH6EHkEa49sWx2SKng"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol":{"keccak256":"0xa535a5df777d44e945dd24aa43a11e44b024140fc340ad0dfe42acf4002aade1","urls":["bzz-raw://41319e7f621f2dc3733511332c4fd032f8e32ad2aa7fd6f665c19741d9941a34","dweb:/ipfs/QmcYR3bd862GD1Bc7jwrU9bGxrhUu5na1oP964bDCu2id1"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol":{"keccak256":"0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305","urls":["bzz-raw://bd39944e8fc06be6dbe2dd1d8449b5336e23c6a7ba3e8e9ae5ae0f37f35283f5","dweb:/ipfs/QmPV3FGYjVwvKSgAXKUN3r9T9GwniZz83CxBpM7vyj2G53"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol":{"keccak256":"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca","urls":["bzz-raw://5a376d3dda2cb70536c0a45c208b29b34ac560c4cb4f513a42079f96ba47d2dd","dweb:/ipfs/QmZQg6gn1sUpM8wHzwNvSnihumUCAhxD119MpXeKp8B9s8"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol":{"keccak256":"0xb264c03a3442eb37a68ad620cefd1182766b58bee6cec40343480392d6b14d69","urls":["bzz-raw://28879d01fd22c07b44f006612775f8577defbe459cb01685c5e25cd518c91a71","dweb:/ipfs/QmVgfkwv2Fxw6hhTcDUZhE7NkoSKjab3ipM7UaRbt6uXb5"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol":{"keccak256":"0xabefac93435967b4d36a4fabcbdbb918d1f0b7ae3c3d85bc30923b326c927ed1","urls":["bzz-raw://9d213d3befca47da33f6db0310826bcdb148299805c10d77175ecfe1d06a9a68","dweb:/ipfs/QmRgCn6SP1hbBkExUADFuDo8xkT4UU47yjNF5FhCeRbQmS"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/Address.sol":{"keccak256":"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa","urls":["bzz-raw://2455248c8ddd9cc6a7af76a13973cddf222072427e7b0e2a7d1aff345145e931","dweb:/ipfs/QmfYjnjRbWqYpuxurqveE6HtzsY1Xx323J428AKQgtBJZm"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/Strings.sol":{"keccak256":"0x3088eb2868e8d13d89d16670b5f8612c4ab9ff8956272837d8e90106c59c14a0","urls":["bzz-raw://b81d9ff6559ea5c47fc573e17ece6d9ba5d6839e213e6ebc3b4c5c8fe4199d7f","dweb:/ipfs/QmPCW1bFisUzJkyjroY3yipwfism9RRCigCcK1hbXtVM8n"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol":{"keccak256":"0x809bc3edb4bcbef8263fa616c1b60ee0004b50a8a1bfa164d8f57fd31f520c58","urls":["bzz-raw://8b93a1e39a4a19eba1600b92c96f435442db88cac91e315c8291547a2a7bcfe2","dweb:/ipfs/QmTm34KVe6uZBZwq8dZDNWwPcm24qBJdxqL3rPxBJ4LrMv"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol":{"keccak256":"0x3af3ca86df39aac39a0514c84459d691434a108d2151c8ce9d69f32e315cab80","urls":["bzz-raw://77d1f1cf302cd5e1dfbbb4ce3b281b28e8c52942d4319fce43df2e1b6f02a52d","dweb:/ipfs/QmT6ZXStmK3Knhh9BokeVHQ9HXTBZNgL3Eb1ar1cYg1hWy"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol":{"keccak256":"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b","urls":["bzz-raw://fb0048dee081f6fffa5f74afc3fb328483c2a30504e94a0ddd2a5114d731ec4d","dweb:/ipfs/QmZptt1nmYoA5SgjwnSgWqgUSDgm4q52Yos3xhnMv3MV43"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"keccak256":"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1","urls":["bzz-raw://be161e54f24e5c6fae81a12db1a8ae87bc5ae1b0ddc805d82a1440a68455088f","dweb:/ipfs/QmP7C3CHdY9urF4dEMb9wmsp1wMxHF6nhA2yQE5SKiPAdy"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/math/Math.sol":{"keccak256":"0xe4455ac1eb7fc497bb7402579e7b4d64d928b846fce7d2b6fde06d366f21c2b3","urls":["bzz-raw://cc8841b3cd48ad125e2f46323c8bad3aa0e88e399ec62acb9e57efa7e7c8058c","dweb:/ipfs/QmSqE4mXHA2BXW58deDbXE8MTcsL5JSKNDbm23sVQxRLPS"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol":{"keccak256":"0xf92515413956f529d95977adc9b0567d583c6203fc31ab1c23824c35187e3ddc","urls":["bzz-raw://c50fcc459e49a9858b6d8ad5f911295cb7c9ab57567845a250bf0153f84a95c7","dweb:/ipfs/QmcEW85JRzvDkQggxiBBLVAasXWdkhEysqypj9EaB6H2g6"],"license":"MIT"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/error/ErrDecimalFloat.sol":{"keccak256":"0x3c9e3f5e6b78877add52f397e2cf452e8a1afe6b9e630fc7bbc7c2d6704d07d9","urls":["bzz-raw://9840b88bf5143a94f8e7779390b025dda83530090be3503e110aa2584250c6e4","dweb:/ipfs/QmemaALnbRKFChq5Ec1p4xdar5rDqEvdbQwGb2vzMVWhK9"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/lib/LibDecimalFloat.sol":{"keccak256":"0x5c8820a79da0ac3c8558ae65c8b3b2b4579326755a4914a243f2475c1159b2aa","urls":["bzz-raw://edc7ddd33798964f19aa9183fa0366321f93ab03171ba334192f65bd71a1a53d","dweb:/ipfs/QmYKAKopDLGMWCfTVhwhF3vCGw6wXveKX1uTtxCyvycNkL"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/lib/implementation/LibDecimalFloatImplementation.sol":{"keccak256":"0x182d010eee786cfa19ad44e215332c4e6fd4e9310da3e61ebd17a0309307d6b6","urls":["bzz-raw://1206a9557d6410c30ec82f02d44d3e857d7aabf46d607ee08bf415af14f8a799","dweb:/ipfs/Qmbygfmw9K8YVQdEsNEkkHxTbTiuuDgWt7yB6gMwoYGBcp"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.math.float/src/lib/table/LibLogTable.sol":{"keccak256":"0x412629a161febf0dc9c3bae0cc9fe0b8de8774d37c5f3afde2e2312478d96a98","urls":["bzz-raw://c8da5302117961caad328e80cb28296ea71aadbc291312e37d3db079d84a9777","dweb:/ipfs/QmWYzpex1Xrnjf3QM68n6mGFQ4KxE53fUUyDjwE3zNrtok"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/error/ErrBytes.sol":{"keccak256":"0xdec97437eeba42f5950dc52f89caac433bc11a56a4e14a0f67a521821600c4b6","urls":["bzz-raw://72b96a4ed0d34dab653df0e6eb19d77b3e1c691b8e35543f6f32ae6a44c6312e","dweb:/ipfs/QmNrwwf3La4D25DudigRedu2c7xfx8k7bEzHFVZfpRu3se"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/error/ErrUint256Array.sol":{"keccak256":"0x57b7a7a5cbc2fc97200130e84fde3a8afc14e0729040b14670dacc7f63c3ac5f","urls":["bzz-raw://4e7c7ce525e882db437b488b590fae6a817b282f88d76eb4f56986b549815e57","dweb:/ipfs/QmajzM26fsaFtaAnm5cg1FZrD6N2wkLJHCxa7Atx5x6iAB"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/lib/LibBytes.sol":{"keccak256":"0x6497d17390179a62820805d18a2cf2cdfddbe4990df783bde11cbf82e414fd0e","urls":["bzz-raw://54e8ed63c566d374ca2d89e8109c41267f7ca661e85570c6c7d51193aaca128b","dweb:/ipfs/Qmd6LoUZqg7TbeAx2auk5UkimyMiK4a9GsVMvDeqDRZF3M"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/lib/LibMemCpy.sol":{"keccak256":"0xf0918be203ec6bba9beb5d58b53d4ae66a8d07764ad872518cbbd39fb7eee77e","urls":["bzz-raw://6a71e16de54788fc3d8d84e4866582aa9955dad598c6131b59e2348acaa9596c","dweb:/ipfs/QmSNZ8VCw8zDBNCQ3ovevNqDQmXE8kcvctEXkggunJJe2x"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/lib/LibPointer.sol":{"keccak256":"0x3fc6ff807b57b681e32229380e3eda57107a1ada8dc2c1270daa84c9fca5addc","urls":["bzz-raw://a82b17ddc1db163ec548648c83dd5bb2f9f4441559452933f424e0a8dff48e57","dweb:/ipfs/QmdKoRbEAPxBRHJWWRwjh9Yrps1QXcJuX5mJmua8nvnq7B"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/lib/rain.solmem/src/lib/LibUint256Array.sol":{"keccak256":"0xa3aecfdc5acd9762e80c09cb3993fc5f13f276d1221452856d1d29e8ff2b2b72","urls":["bzz-raw://d8c02db51b5cf8acd99091b59c255a17be0f47d818d4e5d372ff2c6fd00f2ede","dweb:/ipfs/QmXoEUdXzQkCLbcbFEvKtipdPrBhjnrbauHMtqug2j8RZx"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/error/ErrBytecode.sol":{"keccak256":"0x4d740b62c6e81ffdb25a42c72a5bd5ea945659df1bc38510b4e95a9cd3bfe8bb","urls":["bzz-raw://aa05c6e63a9bd9dd722d3824b2ae376d5237c81a189e0e42bf9a1ba33da919d3","dweb:/ipfs/QmPLZtsKPrC9nLwk1jqw7LwwvsXAkxomrtUQLrhiQNWubC"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/IInterpreterCallerV3.sol":{"keccak256":"0x234691f341e7d7f9123bd6be9ce02d4e38ecccc599899f83345e760cdf0d6bb1","urls":["bzz-raw://3d53753fca93e9e57129ca68080904b7336d5a798959dc462851d9bdcdd460d6","dweb:/ipfs/Qmd4HhCSHHpsCFZpAFcXQbUuqCC9zHp4EPwu7syWCetbNW"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/IInterpreterStoreV2.sol":{"keccak256":"0x89b7dfa624962983c42da404fc8653daa29e793a60f11a2d9c8a9cf34caaf71a","urls":["bzz-raw://10dcc56124d4a054ad13227e6098b7ceda11bbeccd8bb38d1e57da542285f72d","dweb:/ipfs/QmUSgcm3Hpifk4GyjGMssJfo2Pea9dMm9sP4AzyzGfVA5c"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/IInterpreterV3.sol":{"keccak256":"0xf7515e68c4ad0218beafff4f59e21bbaf6c1268499515e4b9c28326440c574e1","urls":["bzz-raw://dc3ddb0928de02c43930be791cf3b9c4ab1f2aba2d8acc768f5c746b2e69fd20","dweb:/ipfs/QmRyACpHRo4TQpmpuioQ43oMMaRTSiEt8MMuYzCiwZCGXL"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/IParserV2.sol":{"keccak256":"0x84b444c476b512c70c6ca40867f85597966f932f2bb0db77fe2a5416298cb3e3","urls":["bzz-raw://df1ec34672cbe90ae3c9cbbf43d399e6a2a5b12dfb35d23f05d14ef7205225e2","dweb:/ipfs/QmPPHNfVKkUSDxT2nrWLbGg4xjJZwmx4598EqTayZG4yqw"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IExpressionDeployerV1.sol":{"keccak256":"0xc0afd50701cd68eef984a63862bd6a10552d704cca6e10f06d19d920b0777c98","urls":["bzz-raw://cd3cbfa9159ceed8871f46f62c7ea235ad8537d3c6c1c004152ebf5d2d597346","dweb:/ipfs/QmPSAJXAcmDeK9Qy6s2dXdeu4GJ62FKWa69VBo4ioCPcJ9"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IExpressionDeployerV2.sol":{"keccak256":"0x368ace8d0f82832f08caf264e4194647b9777c0d4a0f22d88236b30c1e4c8a63","urls":["bzz-raw://9c8a2141fcd76d6308156777b0a9e5a4f7f07fb3693461e2c12f07e4d8c87130","dweb:/ipfs/QmPnhPz6sXzh5xBGZobAPY2WJTgvQDiYWRFKavscSPu7T5"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IExpressionDeployerV3.sol":{"keccak256":"0x6f6b03c0f8e37ebe4275e0d27242754c7be815ff091ad0931a7be21ab11de628","urls":["bzz-raw://1f200079a3689e0d0c8efb97040737a2b4113a82f0df5d8319af36d9ad5d8b97","dweb:/ipfs/QmXFzXZasmD9D7pAYC5wBtB748TZajy69V5tmSEXRd1VZk"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterCallerV1.sol":{"keccak256":"0xc01bc48e2479cab07fc799e26c3790c8cf97acc1f0f490c8f456f554d239a505","urls":["bzz-raw://2981aa2eae0d414bc8ad4105bedb05026cfdad7e6af8f23805dba4835ae9fd8a","dweb:/ipfs/QmQRKi5nmatC1UM2sNta9giuJX3xvvLAD5pmCeAsVWF4hF"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterCallerV2.sol":{"keccak256":"0x62c7149e3d28cd9b67d7eed183c4e59cf300689dd5cc363b011cb2cf32c1200d","urls":["bzz-raw://52cf991b2dc9581222520c32cac224f6936c75183e4c6c16fafa4450a05c0de0","dweb:/ipfs/QmZ7fiZYjnDhNnFXYCXC9iSYs8WAAwmsVxBd5XDA1tPPah"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterStoreV1.sol":{"keccak256":"0x7d2bc86fefbe372fc64381b320244fe9dbda1816867f3040c5bb3951869fe6a7","urls":["bzz-raw://90c371494080129d5acd2bc52d092fc5cfe559147f7fc855ed01e62a7837f21e","dweb:/ipfs/QmcNtPDuTxic8zqRFXf1ba6FJKmQXguxiDUY4E7wjyVwU5"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterV1.sol":{"keccak256":"0xe0b94c771a7b6aa05388b4db6e238e36a4653cbfdbd3e54bbcaa7a97fc9491f4","urls":["bzz-raw://59887a7f2ef60669906c5e70831ac0c9a7345313b04efb306235280f85e1db73","dweb:/ipfs/QmP6Ny9m3sPCP65UmgGGpucSMgVAoDv6qURqyxUE95VU5Q"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IInterpreterV2.sol":{"keccak256":"0xa785ce2ac17059933b74aa3c8bd51321694ba8ddf27f2767ef99ea002faae1c6","urls":["bzz-raw://130555df49552cf6865c4e82d6e67dd115151de2cd2161fb138849992d6a7a82","dweb:/ipfs/QmRvrAGrkk3zgiG9Rox7m9wwzJL6B8ZcQAQvJpYKbvXvTS"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/deprecated/IParserV1.sol":{"keccak256":"0x4f6a9e028942cebebfc84328193f1d31807aac292d9b82e2df489064aa913070","urls":["bzz-raw://54073f63db1f652571472cb2d07de297772c2420e1571a0cb9e0a805ee4347e7","dweb:/ipfs/QmXRqBreJvC8MQd5zLNgmPUdfFa4WD6gSoxvD8hecycux4"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/unstable/IInterpreterCallerV4.sol":{"keccak256":"0xedf1a8c0814b72b278a60c6ae7867df832628b8752d53fbd53598daf6f50ddf0","urls":["bzz-raw://e1ab9686ad00c7c71146d6bd696b370b563664979682a77262eac61bb1d1fc44","dweb:/ipfs/QmeNHknab5XJnwxNF6HrMk18Xnv9ycsj1NKsVSmYBJkLWA"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/unstable/IInterpreterStoreV3.sol":{"keccak256":"0xbfa8a7c8920c8aeeb821544d5dfcaae533fa4ddf5939f7c68fcc1df048e24756","urls":["bzz-raw://7f46c0fde6d5adb57e0459a5864103c33191452b0656316bd4687ab32aa8c77d","dweb:/ipfs/QmdCcxQAkK3RvDDuZpdZo4tr6oUf6PDhptfjr2dDTjsd4U"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/interface/unstable/IInterpreterV4.sol":{"keccak256":"0x21328db6613f5d669637e97fefa1c17c4975e3af195e66a3ee538bd85c4a2ec4","urls":["bzz-raw://1cca4fca2a64b39230242f7938ef25368753791c40a9e184755eb810c8b64054","dweb:/ipfs/QmZMJ2EMX9wcfnD1WDpTrknRjGA3okymAPLw1Fbrqgz7N9"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/bytecode/LibBytecode.sol":{"keccak256":"0x4d4554be5092bb334a78064679423e9a466767a5ba5ad38669bbf2c70cbcddcf","urls":["bzz-raw://3fdc83b600be2d3fa782ae3ecd1f3be3d3c262eef9d4d45370eea2d8c990b160","dweb:/ipfs/QmZTzKXNs8Jsr1HRcfx5Tb3Pem3NqmwVnjiLdoiV45gGSA"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/caller/LibContext.sol":{"keccak256":"0xe9199fe71b30ba63e33b374a9a5145393814ba83b4617e19124db7d057d04bba","urls":["bzz-raw://6eed183238aba53bcec54b9f952ff25cf01814dfa6f09da9754e7a08738432b7","dweb:/ipfs/QmdkRkBBpNWuVHqzoPjy1TUA1MVjaD6RWRFefpYcWnNLFb"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/caller/LibEvaluable.sol":{"keccak256":"0xc6a557258f287f672de835a407740ca614cebe29e7f0ad810d8299142098346a","urls":["bzz-raw://6c7c676affa52e8cf8397f5e1f21928df03fc76cde78800f1c93a6faea5a2ab0","dweb:/ipfs/QmVNrKyn5v3DnRj9p6MVEhu8Z9mpYVHL3nfLXnwwrVBeXU"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/deprecated/caller/LibEncodedDispatch.sol":{"keccak256":"0x9d509dc03442c02d9fc03beb66b1481210f0d6c53f640ee3de06cea93cfa6add","urls":["bzz-raw://dc089b82823cc8e7c65a2c65e31150c74441b10187884c40ad6a992c627e4b04","dweb:/ipfs/QmdA1hdC7mgC4cubyLF4sUt1G2ux7wVLNFye4KKcrg79fa"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/lib/rain.interpreter.interface/src/lib/ns/LibNamespace.sol":{"keccak256":"0xd621d3e5f8b404309ad5d841a3658248e979c1bd59876be3afa7aa0595b4c0e6","urls":["bzz-raw://801fa302f49f3734dd5cc6221dd25f73591ac8feae47351c18e30a98a4ae0ce1","dweb:/ipfs/QmbwXbTSMZ4u6ZsyfseBx79PeHNAWocNHXpgnaPVmLZM38"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/src/interface/IOrderBookV4.sol":{"keccak256":"0x715c5211361bd469a9ec916710611536d087ae5630a3fc3f80e9802ec43c4596","urls":["bzz-raw://c61433f7de82ac5fbd752470aa1b9358dc70455ba85be87a9056509188f5db21","dweb:/ipfs/QmaGvPxe4xpqkVMdq9mo2moJyBHB9f8wTkcxZotk7tevVH"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/src/interface/deprecated/v2/IOrderBookV2.sol":{"keccak256":"0x30c528f1772e9593b5329f1458cab4cce3510a2ccca01696b506af177fffd786","urls":["bzz-raw://9f53c14e5aaab2cd2fbf5b39d07c59acfdc09aff3476345816c2635de2cdd5d3","dweb:/ipfs/QmaomXfmDKdoeYwbMe9cy5anx4fDEMtP4W9Rre5s5DZVE6"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/src/interface/deprecated/v3/IOrderBookV3.sol":{"keccak256":"0xdca3fd0c6106ab98d08682e63e433b74250d1f01e646a5908c97183d9b25130b","urls":["bzz-raw://0f986a8388275a4144068981aa628e46bff221c2d27a3ad597a9c5fc2d4fcb09","dweb:/ipfs/QmR2pxkpY4ddhLb7jdoNAVSJwYHokyGpn5Tzg3Q7YnGYgW"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/src/interface/ierc3156/IERC3156FlashBorrower.sol":{"keccak256":"0xdcd81b1110e9c3c91715ac90aef1da70066bcaba8aeb3dc23df979f7f87644f9","urls":["bzz-raw://4572efaeb9eb30ad9b766b80cb2a8101a2cec0c9e8c78c7696f4aae710c8e2c9","dweb:/ipfs/QmVsz1gtqWfxTAbsoLPvZBe6PBVXqaWNx6nu7RHr2ghLuK"],"license":"CC0-1.0"},"lib/rain.orderbook.interface/src/interface/ierc3156/IERC3156FlashLender.sol":{"keccak256":"0x119c477281a6ec109e9c729a254b39d7ccc9a9f5baa82fa28d0fa1e3bd2b6ae8","urls":["bzz-raw://19ec8289a123459659dca0389a650ca6bf6bc12d925ad7a3e61f0b1bfe68d1b6","dweb:/ipfs/QmRZ9U5ECovPFmbRaBTauFjjVQcvPA7VQL7S1zJVEBTMD5"],"license":"CC0-1.0"},"lib/rain.orderbook.interface/src/interface/unstable/IOrderBookV5.sol":{"keccak256":"0x22e5d686e94d1f38d4361d90197ac606eaacad8dde383c1511707347744bb181","urls":["bzz-raw://175376edb09374551786b57604d04be0b89d2b9aeacb5c6307ce7efb37e41b30","dweb:/ipfs/QmeSjgcBe6SDr5Vbo3QZGsL2NArsUSqPDFSfXiVGi8ftWu"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/src/interface/unstable/IOrderBookV5ArbOrderTaker.sol":{"keccak256":"0xf49109c3736342baac6531dfc53136f7a58e7f3013b8dc2bff6b5a6c7a6922e1","urls":["bzz-raw://a73b0ef285322930745661c634e73c42d262eb741bc11037163808c3e0cfd388","dweb:/ipfs/QmbuYQRczLb1NSKh7j8JqspLTRtusRDQW29oaUtxof6r2A"],"license":"LicenseRef-DCL-1.0"},"lib/rain.orderbook.interface/src/interface/unstable/IOrderBookV5OrderTaker.sol":{"keccak256":"0x76ccb34468d99c23ea5f7361c87741989e3938dc5eb27dbc502f8546d14a9d29","urls":["bzz-raw://1b26eebc3a1bb35684273836a22f56e8fd87e2dd05f6cefe18742834a90a7970","dweb:/ipfs/QmYaB45rjqghoQfcvrUBoScrJkDnM4jGwdAkM5UZtLfusM"],"license":"LicenseRef-DCL-1.0"},"lib/rain.tofu.erc20-decimals/src/interface/ITOFUTokenDecimals.sol":{"keccak256":"0xff728b82d787191dc32f7dac385baa1e194d313c84979b90934e6b8fd06ddbc5","urls":["bzz-raw://e789fb5fcb3396d81fa487c907486b9ba7d33312502b676e43816f777e0379fd","dweb:/ipfs/Qme1evJCUVHVpPteVvgwW84fNAJwLKfVi5xmJjNrhKEziR"],"license":"LicenseRef-DCL-1.0"},"lib/rain.tofu.erc20-decimals/src/lib/LibTOFUTokenDecimals.sol":{"keccak256":"0xc76d8a73006c59a80996514333553c8cf67620e725a03fb1ba4be75f2241c3bb","urls":["bzz-raw://ef559d0939d8378db26d4cfa8c4342494135afe360a1884e3ca90502266bb77c","dweb:/ipfs/QmS2B4VD1CdKsou7Hxsk1cYp3cmNiTiQdcihn5j5qP7Yw5"],"license":"LicenseRef-DCL-1.0"},"lib/sushixswap-v2/src/interfaces/IRouteProcessor.sol":{"keccak256":"0x5b2289c992f34dd25943db3cbc27ece8b0a1addeb2631f812e7834b7ae3eac37","urls":["bzz-raw://f21522058b7fe3c18d2353b06a5ddbf2b62d2aceebf7dd6dfdc51b081452bb3f","dweb:/ipfs/QmVkicGnNWgnX1RfXJWPpQaAPbiAQfFwGWigbPi1wu2WiT"],"license":"GPL-3.0-or-later"},"src/abstract/OrderBookV5ArbCommon.sol":{"keccak256":"0xdcf58e56fb28af2a079ee70a0e05e23f04fe05688d5c4a421169388b4678a498","urls":["bzz-raw://3368ca28ddea108ff2268aa4cac6026cfe3e6d76a7fe2e08e3c45c710601e888","dweb:/ipfs/QmS6TTjG6kbYVs7soCygp9AiKN49Lrp7aDrQTjhBssTtgw"],"license":"LicenseRef-DCL-1.0"},"src/abstract/OrderBookV5ArbOrderTaker.sol":{"keccak256":"0xd37da11daba7e13a9ad6f0dc8365360cc5bc25a587c4c2e8ce61ef680d768391","urls":["bzz-raw://b6a7e1ce0f6080ed52c6c391406e2a4afae51308ccf22fe71243cc8212cee30c","dweb:/ipfs/QmUdgd3iXYXorY2uKyUTbiKJdR4eJjj7yFezCShSsxKVeG"],"license":"LicenseRef-DCL-1.0"},"src/concrete/arb/RouteProcessorOrderBookV5ArbOrderTaker.sol":{"keccak256":"0xb4890fc6d6efb23f0a3efdc9dc6aecc4433d4b2f86d1fe1fe84878e67ff738e9","urls":["bzz-raw://dd8dd96f30251937c0c7597eaa8bb2c930f9b98c7cf0134c0270a21c0e23dce9","dweb:/ipfs/QmZVZghmpViQZVDGYTWzvrvaqqpmkNDR8HwjQQydpTTuL8"],"license":"LicenseRef-DCL-1.0"},"src/lib/LibOrderBook.sol":{"keccak256":"0x85084b3b250dadcaedf66a20193c13cb0acfa134a340b6938c2390eb3ca0e4ad","urls":["bzz-raw://34beb9f1fbd20b7d20cf43c5130595b856285c3cf5a5622a25b8a182214d84a4","dweb:/ipfs/QmX1ikfbzJSuQ7xkPzsQzW5gEizVA2jrLUgtKjPTrXfnh2"],"license":"LicenseRef-DCL-1.0"},"src/lib/LibOrderBookArb.sol":{"keccak256":"0x63231331baf261d7a038b62789d55d9b012eacbd322c525d143ea5a8b302a94f","urls":["bzz-raw://7cf33f078a10304ceec5ac2a6b3e0e1e0ff9df1e55f7ea202228ddb0b03c507e","dweb:/ipfs/QmQPrfUeesGp5ipt5GyjPhkW4mwcrL6SpuHpJS9gUXSJEH"],"license":"LicenseRef-DCL-1.0"}},"version":1},"id":126} \ No newline at end of file diff --git a/test/e2e/data.js b/test/e2e/data.js index 5710f58a..c35426fd 100644 --- a/test/e2e/data.js +++ b/test/e2e/data.js @@ -152,6 +152,31 @@ module.exports = [ [LiquidityProviders.AerodromeSlipstream], ["1", "100"], ], + [ + // unique test for aerodrome slipstream + ChainId.BASE, + process?.env?.TEST_BASE_RPC, + 36806200, + [ + USDC[ChainId.BASE], + new Token({ + chainId: ChainId.BASE, + address: "0xfb8718a69aed7726afb3f04d2bd4bfde1bdcb294", + decimals: 6, + symbol: "TRYB", + }), + ], + [ + "0x336307F2d8390035Ba926a61a86b45CA9dC91E57", + "0x8f58955bB4dfF80f956B4683d29b62C984D4657F", + ], + [LiquidityProviders.AerodromeSlipstream], + ["1", "100"], + undefined, + undefined, + undefined, + true, + ], [ ChainId.BSC, process?.env?.TEST_BSC_RPC, diff --git a/test/e2e/e2e.test.js b/test/e2e/e2e.test.js index 52f6a30f..df36cc3e 100644 --- a/test/e2e/e2e.test.js +++ b/test/e2e/e2e.test.js @@ -48,6 +48,7 @@ const { rainterpreterParserV5Deploy, rainterpreterExpressionDeployerV5Deploy, mockSgFromEventV5, + stabullArbDeployV5, } = require("../utils"); const { SharedState } = require("../../src/state"); const balancerHelpers = require("../../src/router/balancer"); @@ -59,6 +60,8 @@ const { USDC } = require("sushi/currency"); const { maxFloat } = require("../../src/common"); const { SolverContracts } = require("../../src/state/contracts"); const { GasManager } = require("../../src/gas"); +const { StabullRouter } = require("../../src/router/stabull"); +const { StabullConstants } = require("../../src/router/stabull/constants"); // run tests on each network in the provided data for (let i = 0; i < testData.length; i++) { @@ -73,6 +76,7 @@ for (let i = 0; i < testData.length; i++) { orderbookAddress, arbAddress, botAddress, + stabullTrade, ] = testData[i]; // if rpc is not defined for a network go to next test @@ -163,6 +167,7 @@ for (let i = 0; i < testData.length; i++) { describe("Orderbook V4", async () => { it(`should clear orders successfully using route processor v${rpVersion}`, async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -446,6 +451,7 @@ for (let i = 0; i < testData.length; i++) { }); it("should clear orders successfully using inter-orderbook", async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -823,6 +829,7 @@ for (let i = 0; i < testData.length; i++) { }); it("should clear orders successfully using against v5 orderbook", async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -1227,6 +1234,7 @@ for (let i = 0; i < testData.length; i++) { }); it("should clear orders successfully using intra-orderbook", async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); const sushiRouterResult = await sushiRouterPromise; @@ -1605,6 +1613,7 @@ for (let i = 0; i < testData.length; i++) { }); it(`should clear orders successfully using balancer router v${rpVersion}`, async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -1927,6 +1936,7 @@ for (let i = 0; i < testData.length; i++) { describe("Orderbook V5", async () => { it(`should clear orders successfully using route processor v${rpVersion}`, async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -2232,6 +2242,7 @@ for (let i = 0; i < testData.length; i++) { }); it("should clear orders successfully using inter-orderbook", async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -2623,6 +2634,7 @@ for (let i = 0; i < testData.length; i++) { }); it("should clear orders successfully against v4 orderbook", async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -3020,6 +3032,7 @@ for (let i = 0; i < testData.length; i++) { }); it("should clear orders successfully using intra-orderbook", async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -3429,6 +3442,7 @@ for (let i = 0; i < testData.length; i++) { }); it("should clear orders successfully using balancer router", async function () { + if (stabullTrade) return; config.rpc = [rpc]; const viemClient = await viem.getPublicClient(); state.client = viemClient; @@ -3769,6 +3783,327 @@ for (let i = 0; i < testData.length; i++) { testSpan.end(); }); + + it("should clear orders successfully using stabull router", async function () { + if (!stabullTrade) return; + config.rpc = [rpc]; + const viemClient = await viem.getPublicClient(); + state.client = viemClient; + state.client.simulateContract = client.simulateContract; + const sushiRouterResult = await sushiRouterPromise; + assert(sushiRouterResult.isOk()); + sushiRouterResult.value.dataFetcher.web3Client.transport.retryCount = 3; + const stabullRouterResult = await StabullRouter.create(chainId, client); + if (stabullRouterResult.isOk()) { + state.router = new RainSolverRouter( + chainId, + client, + sushiRouterResult.value, + undefined, + stabullRouterResult.value, + ); + } else { + return; + } + const testSpan = tracer.startSpan("test-clearing"); + + // reset network before each test + await helpers.reset(rpc, blockNumber); + // get bot signer + const bot = botAddress + ? (await viem.getTestClient({ account: botAddress })) + .extend(publicActions) + .extend(walletActions) + : ( + await viem.getTestClient({ + account: "0x22025257BeF969A81eDaC0b343ce82d777931327", + }) + ) + .extend(publicActions) + .extend(walletActions); + bot.sendTx = async (tx) => { + return await sendTx(bot, tx); + }; + bot.waitUntilFree = async () => { + return await waitUntilFree(bot); + }; + bot.estimateGasCost = async (tx) => { + return await estimateGasCost(bot, tx); + }; + bot.asWriteSigner = () => bot; + bot.waitForReceipt = async (tx) => { + return await tryGetReceipt(bot, tx.hash, 3000, 50); + }; + bot.state = state; + bot.impersonateAccount({ + address: botAddress ?? "0x22025257BeF969A81eDaC0b343ce82d777931327", + }); + await network.provider.send("hardhat_setBalance", [ + bot.account.address, + "0x4563918244F40000", + ]); + bot.BALANCE = ethers.BigNumber.from("0x4563918244F40000"); + bot.BOUNTY = []; + + // deploy contracts + const interpreter = await rainterpreterV5Deploy(); + const store = await rainterpreterStoreV5Deploy(); + const parser = await rainterpreterParserV5Deploy(); + const deployer = await rainterpreterExpressionDeployerV5Deploy({ + interpreter: interpreter.address, + store: store.address, + parser: parser.address, + }); + const orderbook = !orderbookAddress + ? await deployOrderBookV5() + : await ethers.getContractAt(orderbookAbi, orderbookAddress); + + const arb = !arbAddress + ? await arbDeployV5(orderbook.address, config.routeProcessors[rpVersion]) + : await ethers.getContractAt(ABI.Orderbook.V5.Primary.Arb, arbAddress); + + const stabullArb = await stabullArbDeployV5( + orderbook.address, + StabullConstants.Routers[chainId], + ); + + state.appOptions.balancerArbAddress = stabullArb.address; + state.contracts = await SolverContracts.fromAppOptions(viemClient, { + contracts: { + v5: { + dispair: deployer.address, + // sushiArb: arb.address, + stabullArb: stabullArb.address, + }, + }, + }); + + // set up tokens contracts and impersonate owners + const owners = []; + for (let i = 0; i < tokens.length; i++) { + tokens[i].contract = await ethers.getContractAt( + ERC20Artifact.abi, + tokens[i].address, + ); + tokens[i].vaultId = ethers.BigNumber.from(randomUint256()); + tokens[i].depositAmount = ethers.utils.parseUnits( + deposits[i] ?? "100", + tokens[i].decimals, + ); + // owners.push( + // (await viem.getTestClient({account: addressesWithBalance[i]})).extend(publicActions).extend(walletActions) + // // await ethers.getImpersonatedSigner(addressesWithBalance[i]) + // ); + owners.push(await ethers.getImpersonatedSigner(addressesWithBalance[i])); + await network.provider.send("hardhat_setBalance", [ + addressesWithBalance[i], + "0x4563918244F40000", + ]); + } + + // bot original token balances + const originalBotTokenBalances = []; + for (const t of tokens) { + originalBotTokenBalances.push( + await t.contract.balanceOf(bot.account.address), + ); + } + + // dposit and add orders for each owner and return + // the deployed orders in format of a sg query. + // all orders have WETH as output and other specified + // tokens as input + let orders = []; + for (let i = 1; i < tokens.length; i++) { + const depositConfigStruct = { + token: tokens[i].address, + vaultId: tokens[i].vaultId, + amount: tokens[i].depositAmount.toString(), + }; + await tokens[i].contract + .connect(owners[i]) + .approve(orderbook.address, depositConfigStruct.amount); + await orderbook + .connect(owners[i]) + .deposit3( + depositConfigStruct.token, + depositConfigStruct.vaultId, + toFloat(depositConfigStruct.amount, tokens[i].decimals).value, + [], + ); + + // prebuild bytecode: "_ _: 0 max; :;" + const ratio = "0".repeat(64); // 0 + const maxOutput = maxFloat(18).substring(2).padStart(64, "0"); // max + const bytecode = `0x0000000000000000000000000000000000000000000000000000000000000002${maxOutput}${ratio}0000000000000000000000000000000000000000000000000000000000000015020000000c02020002011000000110000100000000`; + const addOrderConfig = { + evaluable: { + interpreter: interpreter.address, + store: store.address, + bytecode, + }, + nonce: "0x" + "0".repeat(63) + "1", + secret: "0x" + "0".repeat(63) + "1", + validInputs: [ + { + token: tokens[0].address, + vaultId: tokens[0].vaultId, + }, + ], + validOutputs: [ + { + token: tokens[i].address, + vaultId: tokens[i].vaultId, + }, + ], + meta: encodeMeta("some_order"), + }; + const tx = await orderbook.connect(owners[i]).addOrder3(addOrderConfig, [ + { + evaluable: { + interpreter: interpreter.address, + store: store.address, + bytecode: + "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000701000000000000", + }, + signedContext: [], + }, + ]); + orders.push( + await mockSgFromEventV5( + await getEventArgs(tx, "AddOrderV3", orderbook), + orderbook, + tokens.map((v) => ({ + ...v.contract, + knownSymbol: v.symbol, + decimals: v.decimals, + })), + ), + ); + } + + // run the clearing process + config.isTest = true; + config.shuffle = false; + config.signer = bot; + config.hops = 2; + config.retries = 1; + config.lps = liquidityProviders; + config.rpVersion = rpVersion; + config.arbAddress = arb.address; + config.balancerArbAddress = stabullArb.address; + config.orderbookAddress = orderbook.address; + config.testBlockNumber = BigInt(blockNumber); + config.testBlockNumberInc = BigInt(blockNumber); // increments during test updating to new block height + config.gasCoveragePercentage = "1"; + config.viemClient = viemClient; + config.accounts = []; + config.mainAccount = bot; + config.gasPriceMultiplier = 107; + config.gasLimitMultiplier = 120; + config.dispair = { + interpreter: interpreter.address, + store: store.address, + deployer: deployer.address, + }; + config.orderbookTradeTypes = { + router: new Set(), + interOrderbook: new Set(), + intraOrderbook: new Set(), + }; + + const orderManager = new OrderManager(state); + for (const order of orders) { + const res = await orderManager.addOrder(order); + assert(res.isOk()); + } + orders = orderManager.getNextRoundOrders(false); + + state.gasPrice = await bot.getGasPrice(); + orderManager.getNextRoundOrders = () => orders; + const rainSolver = new RainSolver( + state, + config, + orderManager, + { + mainSigner: bot, + getRandomSigner: () => bot, + }, + // config, + ); + const { results: reports } = await rainSolver.processNextRound( + undefined, + false, + ); + + // should have cleared correct number of orders + assert.ok( + reports.length == tokens.length - 1, + "Failed to clear all given orders", + ); + + // validate each cleared order + let inputProfit = ethers.constants.Zero; + let gasSpent = ethers.constants.Zero; + for (let i = 0; i < reports.length; i++) { + const report = reports[i].value; + assert.equal(report.status, ProcessOrderStatus.FoundOpportunity); + + const pair = `${tokens[0].symbol}/${tokens[i + 1].symbol}`; + const clearedAmount = ethers.BigNumber.from(report.clearedAmount); + const outputVault = ethers.BigNumber.from( + normalizeFloat( + await orderbook.vaultBalance2( + owners[i + 1].address, + tokens[i + 1].address, + tokens[i + 1].vaultId, + ), + tokens[i + 1].decimals, + ).value, + ); + const inputVault = ethers.BigNumber.from( + normalizeFloat( + await orderbook.vaultBalance2( + owners[0].address, + tokens[0].address, + tokens[0].vaultId, + ), + tokens[0].decimals, + ).value, + ); + const botTokenBalance = await tokens[i + 1].contract.balanceOf( + bot.account.address, + ); + + assert.equal(report.tokenPair, pair); + + // should have cleared equal to vault balance or lower + assert.ok( + tokens[i + 1].depositAmount.gte(clearedAmount), + `Did not clear expected amount for: ${pair}`, + ); + assert.ok( + outputVault.eq(tokens[i + 1].depositAmount.sub(clearedAmount)), + `Unexpected current output vault balance: ${pair}`, + ); + assert.ok( + inputVault.eq(0), + `Unexpected current input vault balance: ${pair}`, + ); + assert.ok( + originalBotTokenBalances[i + 1].eq(botTokenBalance), + `Unexpected current bot ${tokens[i + 1].symbol} balance`, + ); + + // collect all bot's input income (bounty) and gas cost + inputProfit = inputProfit.add( + ethers.utils.parseUnits(report.inputTokenIncome), + ); + gasSpent = gasSpent.add(ethers.utils.parseUnits(report.gasCost.toString())); + } + + testSpan.end(); + }); }); } }); diff --git a/test/utils.js b/test/utils.js index a417ec74..a5bd8347 100644 --- a/test/utils.js +++ b/test/utils.js @@ -17,6 +17,7 @@ const RainterpreterExpressionDeployerArtifact = require("./abis/RainterpreterExp const GenericPoolOrderBookV5ArbOrderTakerArtifact = require("./abis/GenericPoolOrderBookV5ArbOrderTaker.json"); const RouteProcessorOrderBookV5ArbOrderTakerArtifact = require("./abis/RouteProcessorOrderBookV5ArbOrderTaker.json"); const BalancerRouterOrderBookV5ArbOrderTakerArtifact = require("./abis/BalancerRouterOrderBookV5ArbOrderTaker.json"); +const StabullRouterOrderBookV5ArbOrderTakerArtifact = require("./abis/StabullRouterOrderBookV5ArbOrderTaker.json"); /** * Deploys a simple contracts that takes no arguments for deployment @@ -118,6 +119,17 @@ exports.genericArbrbDeployV5 = async (orderbookAddress) => { }); }; +exports.stabullArbDeployV5 = async (orderbookAddress, routerAddress) => { + return await this.basicDeploy(StabullRouterOrderBookV5ArbOrderTakerArtifact, { + orderBook: orderbookAddress ?? `0x${"0".repeat(40)}`, + task: { + evaluable: ABI.Orderbook.V5.DefaultArbEvaluable, + signedContext: [], + }, + implementationData: ethers.utils.defaultAbiCoder.encode(["address"], [routerAddress]), + }); +}; + exports.deployOrderBookV5 = async () => { return await this.basicDeploy(OrderbookV5Artifact); }; From ec870736324ea18e4d9a1993aee1e6266bbcb31b Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Wed, 15 Oct 2025 16:35:25 +0000 Subject: [PATCH 4/7] fixes --- src/config/validators.ts | 16 ++++++++++++++-- src/router/router.ts | 4 ++-- src/router/stabull/index.test.ts | 3 ++- src/router/stabull/index.ts | 6 +++--- src/router/types.ts | 12 ++++++------ src/state/contracts.test.ts | 13 +++++++++++++ src/state/index.ts | 5 ++--- test/e2e/e2e.test.js | 4 ++-- 8 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/config/validators.ts b/src/config/validators.ts index b46ff85b..40347027 100644 --- a/src/config/validators.ts +++ b/src/config/validators.ts @@ -513,7 +513,13 @@ export namespace Validator { true, ); const contracts: AppOptionsContracts = {}; - if (dispairV4 || sushiArbAddressV4 || genericArbAddressV4 || balancerArbAddressV4) { + if ( + dispairV4 || + sushiArbAddressV4 || + genericArbAddressV4 || + balancerArbAddressV4 || + stabullArbAddressV4 + ) { contracts.v4 = { sushiArb: sushiArbAddressV4 as `0x${string}` | undefined, dispair: dispairV4 as `0x${string}` | undefined, @@ -522,7 +528,13 @@ export namespace Validator { stabullArb: stabullArbAddressV4 as `0x${string}` | undefined, }; } - if (dispairV5 || sushiArbAddressV5 || genericArbAddressV5 || balancerArbAddressV5) { + if ( + dispairV5 || + sushiArbAddressV5 || + genericArbAddressV5 || + balancerArbAddressV5 || + stabullArbAddressV5 + ) { contracts.v5 = { sushiArb: sushiArbAddressV5 as `0x${string}` | undefined, dispair: dispairV5 as `0x${string}` | undefined, diff --git a/src/router/router.ts b/src/router/router.ts index 96f00b69..6f7853db 100644 --- a/src/router/router.ts +++ b/src/router/router.ts @@ -259,7 +259,7 @@ export class RainSolverRouter extends RainSolverRouterBase { toToken: Token, fromToken: Token, maximumInputFixed: bigint, - gasPrice: bigint, + gasPriceBI: bigint, routeType: "single" | "multi" = "single", ): bigint | undefined { return this.sushi?.findLargestTradeSize( @@ -267,7 +267,7 @@ export class RainSolverRouter extends RainSolverRouterBase { toToken, fromToken, maximumInputFixed, - gasPrice, + gasPriceBI, routeType, ); } diff --git a/src/router/stabull/index.test.ts b/src/router/stabull/index.test.ts index ad122958..714a42e8 100644 --- a/src/router/stabull/index.test.ts +++ b/src/router/stabull/index.test.ts @@ -260,7 +260,8 @@ describe("test StabullRouter", () => { it("should call findBestRouter correctly and return error result", async () => { const err = new StabullRouterError("some error", StabullRouterErrorType.FetchFailed); const spy = vi.spyOn(router, "findBestRoute"); - spy.mockResolvedValueOnce(Result.err(err)); + spy.mockResolvedValueOnce(Result.err(err)) // initial call + .mockResolvedValueOnce(Result.err(err)); // toUSDC fallback call const result = await router.getMarketPrice({ fromToken: mockTokenIn, diff --git a/src/router/stabull/index.ts b/src/router/stabull/index.ts index 60d697d2..e102d531 100644 --- a/src/router/stabull/index.ts +++ b/src/router/stabull/index.ts @@ -118,16 +118,16 @@ export class StabullRouter extends RainSolverRouterBase { if (!toUsdcQuote?.isOk()) { return Result.err(quoteResult.error); } - const FromUsdcPrice = await params.sushiRouter?.getMarketPrice({ + const fromUsdcPrice = await params.sushiRouter?.getMarketPrice({ ...params, fromToken: USDC[this.chainId as keyof typeof USDC], }); - if (!FromUsdcPrice?.isOk()) { + if (!fromUsdcPrice?.isOk()) { return Result.err(quoteResult.error); } const price = - (toUsdcQuote.value.price * parseUnits(FromUsdcPrice.value.price, 18)) / ONE18; + (toUsdcQuote.value.price * parseUnits(fromUsdcPrice.value.price, 18)) / ONE18; return Result.ok({ price: formatUnits(price, 18) }); } return Result.ok({ price: formatUnits(quoteResult.value.price, 18) }); diff --git a/src/router/types.ts b/src/router/types.ts index 3c0cab67..f02714fc 100644 --- a/src/router/types.ts +++ b/src/router/types.ts @@ -1,10 +1,12 @@ import { SharedState } from "../state"; import { Token } from "sushi/currency"; import { RainSolverSigner } from "../signer"; +import { RainSolverRouterError } from "./error"; import { WasmEncodedError } from "@rainlanguage/float"; -import { SushiRouter, SushiRouterQuote, SushiTradeParams } from "./sushi"; import { maxFloat, minFloat, Result, toFloat } from "../common"; +import { StabullRouterQuote, StabullTradeParams } from "./stabull"; import { BalancerRouterQuote, BalancerTradeParams } from "./balancer"; +import { SushiRouter, SushiRouterQuote, SushiTradeParams } from "./sushi"; import { Account, Chain, maxUint256, PublicClient, Transport } from "viem"; import { Pair, @@ -14,8 +16,6 @@ import { TakeOrdersConfigTypeV3, TakeOrdersConfigTypeV4, } from "../order"; -import { RainSolverRouterError } from "./error"; -import { StabullRouterQuote, StabullTradeParams } from "./stabull"; /** Represents the different router types */ export enum RouterType { @@ -136,7 +136,7 @@ export abstract class RainSolverRouterBase { * @param toToken - The token to trade to * @param fromToken - The token to trade from * @param maximumInputFixed - The maximum input amount (in 18 decimals) - * @param gasPrice - The current gas price (in bigint) + * @param gasPriceBI - The current gas price (in bigint) * @param routeType - The route type, single or multi */ findLargestTradeSize( @@ -144,7 +144,7 @@ export abstract class RainSolverRouterBase { toToken: Token, fromToken: Token, maximumInputFixed: bigint, - gasPrice: bigint, + gasPriceBI: bigint, routeType: "single" | "multi", ): bigint | undefined { // default implementation returns undefined, override in subclass if supported @@ -152,7 +152,7 @@ export abstract class RainSolverRouterBase { toToken; fromToken; maximumInputFixed; - gasPrice; + gasPriceBI; routeType; return undefined; } diff --git a/src/state/contracts.test.ts b/src/state/contracts.test.ts index a2b2e9be..56140c89 100644 --- a/src/state/contracts.test.ts +++ b/src/state/contracts.test.ts @@ -615,6 +615,19 @@ describe("versionAddressGetter", () => { expect(result).toBeUndefined(); }); + it("should return stabullArb for Router tradeType when sushiArb and balancerArb are not available", () => { + const contractsOnlyStabull = { + ...mockContracts, + sushiArb: undefined, + balancerArb: undefined, + }; + const result = versionAddressGetter(contractsOnlyStabull, mockOrder, TradeType.Router); + expect(result).toEqual({ + dispair: mockContracts.dispair, + destination: "0xstabullArbAddress", + }); + }); + it("should return genericArb for InterOrderbook tradeType when available", () => { const result = versionAddressGetter(mockContracts, mockOrder, TradeType.InterOrderbook); diff --git a/src/state/index.ts b/src/state/index.ts index 173d0986..f66f1375 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -1,3 +1,4 @@ +import { GasManager } from "../gas"; import { ChainId } from "sushi/chain"; import { AppOptions } from "../config"; import { Token } from "sushi/currency"; @@ -16,7 +17,6 @@ import { RainSolverRouterError } from "../router/error"; import { ChainConfig, ChainConfigError, getChainConfig } from "./chain"; import { RpcState, rainSolverTransport, RainSolverTransportConfig } from "../rpc"; import { createPublicClient, parseUnits, PublicClient, ReadContractErrorType } from "viem"; -import { GasManager } from "../gas"; /** Enumerates the possible error types that can occur within the chain config */ export enum SharedStateErrorType { @@ -135,8 +135,7 @@ export namespace SharedStateConfig { const routerResult = await RainSolverRouter.create({ chainId, client, - stabullRouter: - options.contracts.v4?.stabullArb || options.contracts.v5?.stabullArb ? true : false, + stabullRouter: !!(options.contracts.v4?.stabullArb || options.contracts.v5?.stabullArb), sushiRouterConfig: { liquidityProviders, sushiRouteProcessor4Address: chainConfig.routeProcessors["4"] as `0x${string}`, diff --git a/test/e2e/e2e.test.js b/test/e2e/e2e.test.js index df36cc3e..df6c30f9 100644 --- a/test/e2e/e2e.test.js +++ b/test/e2e/e2e.test.js @@ -3867,7 +3867,7 @@ for (let i = 0; i < testData.length; i++) { StabullConstants.Routers[chainId], ); - state.appOptions.balancerArbAddress = stabullArb.address; + state.appOptions.stabullArbAddress = stabullArb.address; state.contracts = await SolverContracts.fromAppOptions(viemClient, { contracts: { v5: { @@ -3991,7 +3991,7 @@ for (let i = 0; i < testData.length; i++) { config.lps = liquidityProviders; config.rpVersion = rpVersion; config.arbAddress = arb.address; - config.balancerArbAddress = stabullArb.address; + config.stabullArbAddress = stabullArb.address; config.orderbookAddress = orderbook.address; config.testBlockNumber = BigInt(blockNumber); config.testBlockNumberInc = BigInt(blockNumber); // increments during test updating to new block height From 268266549e6a23f9a729f79d4b7fe1c01fa27e4b Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Wed, 15 Oct 2025 16:44:26 +0000 Subject: [PATCH 5/7] Update types.ts --- src/router/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/router/types.ts b/src/router/types.ts index f02714fc..930f9bab 100644 --- a/src/router/types.ts +++ b/src/router/types.ts @@ -4,9 +4,9 @@ import { RainSolverSigner } from "../signer"; import { RainSolverRouterError } from "./error"; import { WasmEncodedError } from "@rainlanguage/float"; import { maxFloat, minFloat, Result, toFloat } from "../common"; -import { StabullRouterQuote, StabullTradeParams } from "./stabull"; -import { BalancerRouterQuote, BalancerTradeParams } from "./balancer"; -import { SushiRouter, SushiRouterQuote, SushiTradeParams } from "./sushi"; +import type { StabullRouterQuote, StabullTradeParams } from "./stabull"; +import type { BalancerRouterQuote, BalancerTradeParams } from "./balancer"; +import type { SushiRouter, SushiRouterQuote, SushiTradeParams } from "./sushi"; import { Account, Chain, maxUint256, PublicClient, Transport } from "viem"; import { Pair, From e97900dd3a44c3d8fe851f27d832c97b36ff59ac Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 19 Oct 2025 00:41:09 +0000 Subject: [PATCH 6/7] docs [skip ci] --- src/router/stabull/index.ts | 10 +++++++--- src/router/sushi/blacklist.ts | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/router/stabull/index.ts b/src/router/stabull/index.ts index e102d531..a670958d 100644 --- a/src/router/stabull/index.ts +++ b/src/router/stabull/index.ts @@ -49,8 +49,12 @@ export type StabullTradeParams = { }; /** - * The Stabull Router class provides methods to interact with the stabull router library, mainly `RainDataFetcher`, - * including fetching and syncing pool data, getting best route and market price. + * The Stabull Router class provides methods to interact with the stabull protocol. + * Stabull DEX supports very limited set of tokens and it can only support a trade + * when both IO tokens are supported (this is done through `canTrade` static method). + * For finding the best route and quoting, we just need to call its `Router` contract + * functions on the supported chains. + * List of supported chains, tokens and pools can be found in {@link StabullConstants} */ export class StabullRouter extends RainSolverRouterBase { /** The address of the router contract */ @@ -70,7 +74,7 @@ export class StabullRouter extends RainSolverRouterBase { } /** - * Tries to initialize the Stabull Router instance from the given params + * Tries to initialize the Stabull Router for the given chain id and viem client * @param chainId - The chain id of the operating chain * @param client - A viem client instance * @returns A Result containing the Stabull Router instance or an error diff --git a/src/router/sushi/blacklist.ts b/src/router/sushi/blacklist.ts index bafb84c9..910351c9 100644 --- a/src/router/sushi/blacklist.ts +++ b/src/router/sushi/blacklist.ts @@ -2,10 +2,10 @@ import { RPool } from "sushi/tines"; /** Blacklisted pools */ export const BlackList = [ - "0x2c2797Fe74A1b40E3B85b82c02C0AC327D9dF22D", - "0xFB957DE375cc10450D7a34aB85b1F15Ef58680b4", - "0x11E29b541AbE15984c863c10F3Ef9eCBcC078031", - "0x59048Ff7D11ef18514163d0A860fb7A34927a452", + "0x2c2797Fe74A1b40E3B85b82c02C0AC327D9dF22D", // polygon quickswap zkRace/USDT + "0xFB957DE375cc10450D7a34aB85b1F15Ef58680b4", // linea USDC/WETH + "0x11E29b541AbE15984c863c10F3Ef9eCBcC078031", // linea USDT/WETH + "0x59048Ff7D11ef18514163d0A860fb7A34927a452", // linea Elk USDC/WETH "0x461053a473248054807241adE4F988A35899A312", // polygon quickswap NHT/WPOL "0xB259dD2307E7626d925efb6D523b986b670e5631", // polygon sushiswap NHT/WPOL "0x2344cD834d03bA94886ca5665F847BbDD7484f32", // polygon sushiswap NHT/WETH From c711d9a44d55c3e060f10d7f9ad5249211f0b9ad Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Sun, 19 Oct 2025 02:15:51 +0000 Subject: [PATCH 7/7] update [skip ci] --- src/router/stabull/index.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/router/stabull/index.ts b/src/router/stabull/index.ts index a670958d..4ad960e3 100644 --- a/src/router/stabull/index.ts +++ b/src/router/stabull/index.ts @@ -257,7 +257,7 @@ export class StabullRouter extends RainSolverRouterBase { * @returns True if the trade is possible for the given token pair, false otherwise */ static canTrade(fromToken: `0x${string}`, toToken: `0x${string}`, chainId: number): boolean { - if ( + return ( StabullConstants.isChainSupported(chainId) && StabullConstants.TokenList[chainId as keyof typeof StabullConstants.TokenList].has( fromToken.toLowerCase(), @@ -265,9 +265,6 @@ export class StabullRouter extends RainSolverRouterBase { StabullConstants.TokenList[chainId as keyof typeof StabullConstants.TokenList].has( toToken.toLowerCase(), ) - ) { - return true; - } - return false; + ); } }